diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-07-24 21:52:56 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-07-24 21:52:56 +0200 |
commit | 0e90167647a53978705618f435e3d96454e6b6cf (patch) | |
tree | c0c58af1780ccef1c312fb1cfb7144b460a4f8d2 /pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch | |
parent | pkgs/tskm: Support raw paths in place of URLs (diff) | |
download | nixos-config-0e90167647a53978705618f435e3d96454e6b6cf.zip |
pkgs/i3status-rust: Inline the patches
The github patches seem to change their hash from time to time?
Diffstat (limited to 'pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch')
-rw-r--r-- | pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch b/pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch new file mode 100644 index 00000000..8ef0af2e --- /dev/null +++ b/pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch @@ -0,0 +1,190 @@ +From 78d2936b67064e3b5e700a2859d00ea3dd6eda4c Mon Sep 17 00:00:00 2001 +From: Benedikt Peetz <benedikt.peetz@b-peetz.de> +Date: Sun, 18 May 2025 20:22:04 +0200 +Subject: [PATCH 1/3] disk_space: Support btrfs backend + +Btrfs is too smart for the statvfs based backend (i.e., only counting +blocks leads to wrong numbers). + +For example, a btrfs disk with a lot of de-duplicated blocks (via the copy +on write mechanism) might have a drastically over-reported disk usage. + +The btrfs backend is currently implemented by parsing the output of the +`btrfs filesystem usage --raw` command. This is suboptimal, as this now +relies on the command output not changing. + +Vendoring the algorithm used internally by the `btrfs` command does not +seem to be a reasonable alternative, considering that the code[1] is +rather complex, low level and would require semi-constant maintenance. +Additionally, the c code would need bindings to be usable from rust. + +I assume, that the `btrfs` command output will stay rather similar in +the future, as a lot of tools rely on directly parsing it (see the +various scripts in the issue, this commit fixes). + +[1]: https://github.com/kdave/btrfs-progs/blob/eeab081e9d9fbdf4583122ed1caedf541383cf2d/cmds/filesystem-usage.c#L442 + +Fixes: #1654 +--- + src/blocks/disk_space.rs | 112 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 101 insertions(+), 11 deletions(-) + +diff --git a/src/blocks/disk_space.rs b/src/blocks/disk_space.rs +index 79bfebd27..da0d3f518 100644 +--- a/src/blocks/disk_space.rs ++++ b/src/blocks/disk_space.rs +@@ -12,6 +12,7 @@ + //! `alert` | A value which will trigger critical block state | `10.0` + //! `info_type` | Determines which information will affect the block state. Possible values are `"available"`, `"free"` and `"used"` | `"available"` + //! `alert_unit` | The unit of `alert` and `warning` options. If not set, percents are used. Possible values are `"B"`, `"KB"`, `"KiB"`, `"MB"`, `"MiB"`, `"GB"`, `"Gib"`, `"TB"` and `"TiB"` | `None` ++//! `backend` | The backend to use when querying disk usage. Possible values are `"vfs"` (like `du(1)`) and `"btrfs"` | `"vfs"` + //! + //! Placeholder | Value | Type | Unit + //! -------------|--------------------------------------------------------------------|--------|------- +@@ -63,9 +64,12 @@ + + // make_log_macro!(debug, "disk_space"); + ++use std::cell::OnceCell; ++ + use super::prelude::*; + use crate::formatting::prefix::Prefix; + use nix::sys::statvfs::statvfs; ++use tokio::process::Command; + + #[derive(Copy, Clone, Debug, Deserialize, SmartDefault)] + #[serde(rename_all = "lowercase")] +@@ -76,11 +80,20 @@ pub enum InfoType { + Used, + } + ++#[derive(Copy, Clone, Debug, Deserialize, SmartDefault)] ++#[serde(rename_all = "lowercase")] ++pub enum Backend { ++ #[default] ++ Vfs, ++ Btrfs, ++} ++ + #[derive(Deserialize, Debug, SmartDefault)] + #[serde(deny_unknown_fields, default)] + pub struct Config { + #[default("/".into())] + pub path: ShellString, ++ pub backend: Backend, + pub info_type: InfoType, + pub format: FormatConfig, + pub format_alt: Option<FormatConfig>, +@@ -128,17 +141,9 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> { + loop { + let mut widget = Widget::new().with_format(format.clone()); + +- let statvfs = statvfs(&*path).error("failed to retrieve statvfs")?; +- +- // Casting to be compatible with 32-bit systems +- #[allow(clippy::unnecessary_cast)] +- let (total, used, available, free) = { +- let total = (statvfs.blocks() as u64) * (statvfs.fragment_size() as u64); +- let used = ((statvfs.blocks() as u64) - (statvfs.blocks_free() as u64)) +- * (statvfs.fragment_size() as u64); +- let available = (statvfs.blocks_available() as u64) * (statvfs.block_size() as u64); +- let free = (statvfs.blocks_free() as u64) * (statvfs.block_size() as u64); +- (total, used, available, free) ++ let (total, used, available, free) = match config.backend { ++ Backend::Vfs => get_vfs(&*path)?, ++ Backend::Btrfs => get_btrfs(&path).await?, + }; + + let result = match config.info_type { +@@ -205,3 +210,88 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> { + } + } + } ++ ++fn get_vfs<P>(path: &P) -> Result<(u64, u64, u64, u64)> ++where ++ P: ?Sized + nix::NixPath, ++{ ++ let statvfs = statvfs(path).error("failed to retrieve statvfs")?; ++ ++ // Casting to be compatible with 32-bit systems ++ #[allow(clippy::unnecessary_cast)] ++ { ++ let total = (statvfs.blocks() as u64) * (statvfs.fragment_size() as u64); ++ let used = ((statvfs.blocks() as u64) - (statvfs.blocks_free() as u64)) ++ * (statvfs.fragment_size() as u64); ++ let available = (statvfs.blocks_available() as u64) * (statvfs.block_size() as u64); ++ let free = (statvfs.blocks_free() as u64) * (statvfs.block_size() as u64); ++ ++ Ok((total, used, available, free)) ++ } ++} ++ ++async fn get_btrfs(path: &str) -> Result<(u64, u64, u64, u64)> { ++ const OUTPUT_CHANGED: &str = "Btrfs filesystem usage output format changed"; ++ ++ fn remove_estimate_min(estimate_str: &str) -> Result<&str> { ++ estimate_str.trim_matches('\t') ++ .split_once("\t") ++ .ok_or(Error::new(OUTPUT_CHANGED)) ++ .map(|v| v.0) ++ } ++ ++ macro_rules! get { ++ ($source:expr, $name:expr, $variable:ident) => { ++ get!(@pre_op (|a| {Ok::<_, Error>(a)}), $source, $name, $variable) ++ }; ++ (@pre_op $function:expr, $source:expr, $name:expr, $variable:ident) => { ++ if $source.starts_with(concat!($name, ":")) { ++ let (found_name, variable_str) = ++ $source.split_once(":").ok_or(Error::new(OUTPUT_CHANGED))?; ++ ++ let variable_str = $function(variable_str)?; ++ ++ debug_assert_eq!(found_name, $name); ++ $variable ++ .set(variable_str.trim().parse().error(OUTPUT_CHANGED)?) ++ .map_err(|_| Error::new(OUTPUT_CHANGED))?; ++ } ++ }; ++ } ++ ++ let filesystem_usage = Command::new("btrfs") ++ .args(["filesystem", "usage", "--raw", path]) ++ .output() ++ .await ++ .error("Failed to collect btrfs filesystem usage info")? ++ .stdout; ++ ++ { ++ let final_total = OnceCell::new(); ++ let final_used = OnceCell::new(); ++ let final_free = OnceCell::new(); ++ ++ let mut lines = filesystem_usage.lines(); ++ while let Some(line) = lines ++ .next_line() ++ .await ++ .error("Failed to read output of btrfs filesystem usage")? ++ { ++ let line = line.trim(); ++ ++ // See btrfs-filesystem(8) for an explanation for the rows. ++ get!(line, "Device size", final_total); ++ get!(line, "Used", final_used); ++ get!(@pre_op remove_estimate_min, line, "Free (estimated)", final_free); ++ } ++ ++ Ok(( ++ *final_total.get().ok_or(Error::new(OUTPUT_CHANGED))?, ++ *final_used.get().ok_or(Error::new(OUTPUT_CHANGED))?, ++ // HACK(@bpeetz): We also return the free disk space as the available one, because btrfs ++ // does not tell us which disk space is reserved for the fs. <2025-05-18> ++ *final_free.get().ok_or(Error::new(OUTPUT_CHANGED))?, ++ *final_free.get().ok_or(Error::new(OUTPUT_CHANGED))?, ++ )) ++ } ++} +-- +2.49.0 + |