From 19faf774e7b526e3d6d945789562939cdbaa442e Mon Sep 17 00:00:00 2001
From: Aelin <aelin@postmarketos.org>
Date: Wed, 29 Apr 2026 01:57:49 +0200
Subject: [PATCH] df: add a fallback path for statfs with a mount table

There are situations where the mount table would not contain
an entry for /, so df /usr would fail if there was not a mount
entry for / or /usr. GNU coreutils however behave a little
different here: it seems like they also use the statfs fallback
to find the filesystem that the path is on and then print the
last mountpoint in the mount table that is on the same filesystem.
Add such a fallback.

Bug-Ubuntu: https://launchpad.net/bugs/2116290
Origin: other, https://github.com/uutils/coreutils/pull/12072
Forwarded: not-needed

--- a/src/uu/df/src/df.rs
+++ b/src/uu/df/src/df.rs
@@ -386,7 +386,8 @@ where
         let fs_result = if use_fallback {
             Filesystem::from_path_direct(path)
         } else {
-            Filesystem::from_path(&mounts, path)
+            Filesystem::from_path(&mounts, path)
+                .or_else(|_| Filesystem::from_path_direct_with_mounts(&mounts, path))
         };
         #[cfg(not(unix))]
         let fs_result = Filesystem::from_path(&mounts, path);
--- a/src/uu/df/src/filesystem.rs
+++ b/src/uu/df/src/filesystem.rs
@@ -228,6 +228,39 @@ impl Filesystem {
         return result.and_then(|mount_info| Self::from_mount(mounts, mount_info, Some(file)));
     }

+    /// Fallback using statfs with a mount table available.
+    #[cfg(unix)]
+    pub(crate) fn from_path_direct_with_mounts<P>(
+        mounts: &[MountInfo],
+        path: P,
+    ) -> Result<Self, FsError>
+    where
+        P: AsRef<Path>,
+    {
+        let file = path.as_ref().as_os_str().to_owned();
+
+        let canonical_path = path
+            .as_ref()
+            .canonicalize()
+            .map_err(|_| FsError::InvalidPath)?;
+
+        let stat_result = statfs(canonical_path.as_os_str()).map_err(|_| FsError::MountMissing)?;
+
+        // GNU coreutils always appear to return the last match
+        let mut last_match = None;
+        for mount in mounts {
+            if let Ok(stat_result_mount) = statfs(&mount.mount_dir)
+                && stat_result_mount.fsid() == stat_result.fsid()
+            {
+                last_match = Some(mount);
+            }
+        }
+
+        last_match
+            .ok_or(FsError::MountMissing)
+            .and_then(|mount_info| Self::from_mount(mounts, mount_info, Some(file)))
+    }
+
     /// Fallback using statfs when mount table is unavailable.
     #[cfg(unix)]
     pub(crate) fn from_path_direct<P>(path: P) -> Result<Self, FsError>
