aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/i3
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-07-24 21:52:56 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-07-24 21:52:56 +0200
commit0e90167647a53978705618f435e3d96454e6b6cf (patch)
treec0c58af1780ccef1c312fb1cfb7144b460a4f8d2 /pkgs/by-name/i3
parentpkgs/tskm: Support raw paths in place of URLs (diff)
downloadnixos-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')
-rw-r--r--pkgs/by-name/i3/i3status-rust-patched/package.nix13
-rw-r--r--pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch190
-rw-r--r--pkgs/by-name/i3/i3status-rust-patched/patches/0002-memory-Directly-convert-reported-memory-usage-into-b.patch117
-rw-r--r--pkgs/by-name/i3/i3status-rust-patched/patches/0003-memory-Avoid-estimating-available-memory-use-kernel-.patch49
4 files changed, 359 insertions, 10 deletions
diff --git a/pkgs/by-name/i3/i3status-rust-patched/package.nix b/pkgs/by-name/i3/i3status-rust-patched/package.nix
index 9f172d49..1d0a42bc 100644
--- a/pkgs/by-name/i3/i3status-rust-patched/package.nix
+++ b/pkgs/by-name/i3/i3status-rust-patched/package.nix
@@ -18,17 +18,10 @@ i3status-rust.overrideAttrs (final: prev: {
(prev.patches or [])
++ [
# Btrfs support for disk_space block.
- (fetchpatch2 {
- name = "disk_space: Support btrfs backend";
- url = "https://patch-diff.githubusercontent.com/raw/greshake/i3status-rust/pull/2159.patch";
- hash = "sha256-S2/biX6FTLJNfI9QVgwr+V8IGMRnSFIZnTrhc+1LvqQ=";
- })
+ ./patches/0001-disk_space-Support-btrfs-backend.patch
# Correctly calculate the used memory.
- (fetchpatch2 {
- name = "memory: Avoid estimating available memory, use kernel estimate instead";
- url = "https://patch-diff.githubusercontent.com/raw/greshake/i3status-rust/pull/2160.patch";
- hash = "sha256-1wB2KpXhC/UIxAgRioOYj/bnrzRSuaHAdbeoZ2O5E/Y=";
- })
+ ./patches/0002-memory-Directly-convert-reported-memory-usage-into-b.patch
+ ./patches/0003-memory-Avoid-estimating-available-memory-use-kernel-.patch
];
})
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
+
diff --git a/pkgs/by-name/i3/i3status-rust-patched/patches/0002-memory-Directly-convert-reported-memory-usage-into-b.patch b/pkgs/by-name/i3/i3status-rust-patched/patches/0002-memory-Directly-convert-reported-memory-usage-into-b.patch
new file mode 100644
index 00000000..00a50e92
--- /dev/null
+++ b/pkgs/by-name/i3/i3status-rust-patched/patches/0002-memory-Directly-convert-reported-memory-usage-into-b.patch
@@ -0,0 +1,117 @@
+From fccc34618103126d9374a5361a5870ccf8030fa0 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 19 May 2025 21:26:57 +0200
+Subject: [PATCH 2/3] memory: Directly convert reported memory usage into bytes
+
+`/proc/meminfo` states that it's report values are in KB, when
+they actually are in KiB. Previously, this inconsistency leaked into the
+whole code for this block (which had to add `* 1024` after nearly every
+assignment). Now this inconsistency is contained to the `Memstate`
+structure.
+---
+ src/blocks/memory.rs | 53 +++++++++++++++++++++++---------------------
+ 1 file changed, 28 insertions(+), 25 deletions(-)
+
+diff --git a/src/blocks/memory.rs b/src/blocks/memory.rs
+index 801e61de0..8cf32f9ba 100644
+--- a/src/blocks/memory.rs
++++ b/src/blocks/memory.rs
+@@ -112,8 +112,8 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+ loop {
+ let mem_state = Memstate::new().await?;
+
+- let mem_total = mem_state.mem_total as f64 * 1024.;
+- let mem_free = mem_state.mem_free as f64 * 1024.;
++ let mem_total = mem_state.mem_total as f64;
++ let mem_free = mem_state.mem_free as f64;
+
+ // TODO: possibly remove this as it is confusing to have `mem_total_used` and `mem_used`
+ // htop and such only display equivalent of `mem_used`
+@@ -126,8 +126,7 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+ min(mem_state.mem_available, mem_state.mem_total)
+ } else {
+ mem_state.mem_free
+- } as f64
+- * 1024.;
++ } as f64;
+
+ // While zfs_arc_cache can be considered "available" memory,
+ // it can only free a maximum of (zfs_arc_cache - zfs_arc_min) amount.
+@@ -137,14 +136,14 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+ .saturating_sub(mem_state.zfs_arc_min) as f64;
+ let mem_avail = mem_avail + zfs_shrinkable_size;
+
+- let pagecache = mem_state.pagecache as f64 * 1024.;
+- let reclaimable = mem_state.s_reclaimable as f64 * 1024.;
+- let shmem = mem_state.shmem as f64 * 1024.;
++ let pagecache = mem_state.pagecache as f64;
++ let reclaimable = mem_state.s_reclaimable as f64;
++ let shmem = mem_state.shmem as f64;
+
+ // See https://lore.kernel.org/lkml/1455827801-13082-1-git-send-email-hannes@cmpxchg.org/
+ let cached = pagecache + reclaimable - shmem + zfs_shrinkable_size;
+
+- let buffers = mem_state.buffers as f64 * 1024.;
++ let buffers = mem_state.buffers as f64;
+
+ // same logic as htop
+ let used_diff = mem_free + buffers + pagecache + reclaimable;
+@@ -157,14 +156,14 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+ // account for ZFS ARC cache
+ let mem_used = mem_used - zfs_shrinkable_size;
+
+- let swap_total = mem_state.swap_total as f64 * 1024.;
+- let swap_free = mem_state.swap_free as f64 * 1024.;
+- let swap_cached = mem_state.swap_cached as f64 * 1024.;
++ let swap_total = mem_state.swap_total as f64;
++ let swap_free = mem_state.swap_free as f64;
++ let swap_cached = mem_state.swap_cached as f64;
+ let swap_used = swap_total - swap_free - swap_cached;
+
+ // Zswap usage
+- let zswap_compressed = mem_state.zswap_compressed as f64 * 1024.;
+- let zswap_decompressed = mem_state.zswap_decompressed as f64 * 1024.;
++ let zswap_compressed = mem_state.zswap_compressed as f64;
++ let zswap_decompressed = mem_state.zswap_decompressed as f64;
+
+ let zswap_comp_ratio = if zswap_compressed != 0.0 {
+ zswap_decompressed / zswap_compressed
+@@ -310,19 +309,23 @@ impl Memstate {
+ .and_then(|x| u64::from_str(x).ok())
+ .error("failed to parse /proc/meminfo")?;
+
++ // These values are reported as “kB” but are actually “kiB”.
++ // Convert them into bytes to avoid having to handle this later.
++ // Source: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-meminfo#s2-proc-meminfo
++ const KIB: u64 = 1024;
+ match name {
+- "MemTotal:" => mem_state.mem_total = val,
+- "MemFree:" => mem_state.mem_free = val,
+- "MemAvailable:" => mem_state.mem_available = val,
+- "Buffers:" => mem_state.buffers = val,
+- "Cached:" => mem_state.pagecache = val,
+- "SReclaimable:" => mem_state.s_reclaimable = val,
+- "Shmem:" => mem_state.shmem = val,
+- "SwapTotal:" => mem_state.swap_total = val,
+- "SwapFree:" => mem_state.swap_free = val,
+- "SwapCached:" => mem_state.swap_cached = val,
+- "Zswap:" => mem_state.zswap_compressed = val,
+- "Zswapped:" => mem_state.zswap_decompressed = val,
++ "MemTotal:" => mem_state.mem_total = val * KIB,
++ "MemFree:" => mem_state.mem_free = val * KIB,
++ "MemAvailable:" => mem_state.mem_available = val * KIB,
++ "Buffers:" => mem_state.buffers = val * KIB,
++ "Cached:" => mem_state.pagecache = val * KIB,
++ "SReclaimable:" => mem_state.s_reclaimable = val * KIB,
++ "Shmem:" => mem_state.shmem = val * KIB,
++ "SwapTotal:" => mem_state.swap_total = val * KIB,
++ "SwapFree:" => mem_state.swap_free = val * KIB,
++ "SwapCached:" => mem_state.swap_cached = val * KIB,
++ "Zswap:" => mem_state.zswap_compressed = val * KIB,
++ "Zswapped:" => mem_state.zswap_decompressed = val * KIB,
+ _ => (),
+ }
+
+--
+2.49.0
+
diff --git a/pkgs/by-name/i3/i3status-rust-patched/patches/0003-memory-Avoid-estimating-available-memory-use-kernel-.patch b/pkgs/by-name/i3/i3status-rust-patched/patches/0003-memory-Avoid-estimating-available-memory-use-kernel-.patch
new file mode 100644
index 00000000..8943796d
--- /dev/null
+++ b/pkgs/by-name/i3/i3status-rust-patched/patches/0003-memory-Avoid-estimating-available-memory-use-kernel-.patch
@@ -0,0 +1,49 @@
+From b7ae3bd9672e7e1a3fc8e75d90b5bcbe75e6febf Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Mon, 19 May 2025 21:29:54 +0200
+Subject: [PATCH 3/3] memory: Avoid estimating available memory, use kernel
+ estimate instead
+
+`free`, `btop` and other tools (like the `sysinfo` rust library)
+use `mem_total - mem_avail` to calculate the used memory. As explained
+in the already linked [kernel commit][1], `mem_avail` is an estimate of
+the available memory based on the current way the kernel handles
+memory.
+
+The previous logic for calculating used memory tried to estimate
+this based on `mem_free`, `buffers`, `pagecache` and
+`reclaimable`. Unfortunately, as the kernel commit message predicts,
+this user space estimate bitrots, as the kernel memory usage patterns change.
+
+Thus, we now simply use the kernel estimate `mem_avail` as we know that
+that is in-sync with the relevant kernel internals.
+
+[1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
+---
+ src/blocks/memory.rs | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+diff --git a/src/blocks/memory.rs b/src/blocks/memory.rs
+index 8cf32f9ba..94d8a5fe3 100644
+--- a/src/blocks/memory.rs
++++ b/src/blocks/memory.rs
+@@ -145,13 +145,9 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+
+ let buffers = mem_state.buffers as f64;
+
+- // same logic as htop
+- let used_diff = mem_free + buffers + pagecache + reclaimable;
+- let mem_used = if mem_total >= used_diff {
+- mem_total - used_diff
+- } else {
+- mem_total - mem_free
+- };
++ // Userspace should use `mem_avail` for estimating the memory that is available.
++ // See: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
++ let mem_used = mem_total - mem_avail;
+
+ // account for ZFS ARC cache
+ let mem_used = mem_used - zfs_shrinkable_size;
+--
+2.49.0
+