From e152ebaeadfd9f364c771a121d6a5bd97bc7b891 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 25 Mar 2022 10:46:13 +0100 Subject: [PATCH] df: fix calculation of Use% column Change formula from: "Used/Size * 100" to "Used/(Used + Avail) * 100". This formula also works if "Used" and "Avail" do not add up to "Size", which is the case if there are reserved disk blocks. --- src/uu/df/src/table.rs | 10 +++++++--- tests/by-util/test_df.rs | 25 ++++++++----------------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/uu/df/src/table.rs b/src/uu/df/src/table.rs index a99adaa6c..39c762711 100644 --- a/src/uu/df/src/table.rs +++ b/src/uu/df/src/table.rs @@ -149,24 +149,28 @@ impl From for Row { ffree, .. } = fs.usage; + let bused = blocks - bfree; Self { file: fs.file, fs_device: dev_name, fs_type, fs_mount: mount_dir, bytes: blocksize * blocks, - bytes_used: blocksize * (blocks - bfree), + bytes_used: blocksize * bused, bytes_avail: blocksize * bavail, bytes_usage: if blocks == 0 { None } else { - Some(((blocks - bfree) as f64) / blocks as f64) + // We use "(bused + bavail)" instead of "blocks" because on some filesystems (e.g. + // ext4) "blocks" also includes reserved blocks we ignore for the usage calculation. + // https://www.gnu.org/software/coreutils/faq/coreutils-faq.html#df-Size-and-Used-and-Available-do-not-add-up + Some((bused as f64) / (bused + bavail) as f64) }, #[cfg(target_os = "macos")] bytes_capacity: if bavail == 0 { None } else { - Some(bavail as f64 / ((blocks - bfree + bavail) as f64)) + Some(bavail as f64 / ((bused + bavail) as f64)) }, inodes: files, inodes_used: files - ffree, diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index b178c40c0..87fd04312 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore udev +// spell-checker:ignore udev pcent use crate::common::util::*; #[test] @@ -139,33 +139,24 @@ fn test_total() { #[test] fn test_use_percentage() { - // Example output: - // - // Filesystem 1K-blocks Used Available Use% Mounted on - // udev 3858016 0 3858016 0% /dev - // ... - // /dev/loop14 63488 63488 0 100% /snap/core20/1361 - let output = new_ucmd!().succeeds().stdout_move_str(); + let output = new_ucmd!() + .args(&["--output=used,avail,pcent"]) + .succeeds() + .stdout_move_str(); // Skip the header line. let lines: Vec<&str> = output.lines().skip(1).collect(); for line in lines { let mut iter = line.split_whitespace(); - iter.next(); - let reported_size = iter.next().unwrap().parse::().unwrap(); let reported_used = iter.next().unwrap().parse::().unwrap(); - // Skip "Available" column - iter.next(); - if cfg!(target_os = "macos") { - // Skip "Capacity" column - iter.next(); - } + let reported_avail = iter.next().unwrap().parse::().unwrap(); let reported_percentage = iter.next().unwrap(); let reported_percentage = reported_percentage[..reported_percentage.len() - 1] .parse::() .unwrap(); - let computed_percentage = (100.0 * (reported_used / reported_size)).ceil() as u8; + let computed_percentage = + (100.0 * (reported_used / (reported_used + reported_avail))).ceil() as u8; assert_eq!(computed_percentage, reported_percentage); }