Consider these standard bind mounts on my system:

$ grep sdb2 /proc/mounts
/dev/sdb2 / ext4 rw,seclabel,relatime,user_xattr,barrier=1,data=ordered 0 0
/dev/sdb2 /tmp ext4 rw,seclabel,relatime,user_xattr,barrier=1,data=ordered 0 0
/dev/sdb2 /var/tmp ext4 rw,seclabel,relatime,user_xattr,barrier=1,data=ordered 
0 0

Current df picks the last one:

$ df -h /dev/sdb2
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb2        13G  8.0G  4.5G  64% /var/tmp

The attached patch uses the same technique as when handling
non device node arguments, to use the shortest mount point:

$ src/df /dev/sdb2
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb2        13G  8.0G  4.5G  64% /

thanks,
Pádraig.
>From 2b2f0805bcf0cd9c1f7a4af50b4d912aa475f40e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Wed, 4 Dec 2013 00:50:10 +0000
Subject: [PATCH] df: handle bind mounts when processing device nodes

* src/df.c (get_disk): Use the same heuristic used in
get_point() to select the shortest file system mount point,
in an attempt to show the base mounted file system.
* NEWS: Mention the bug fix.
---
 NEWS     |    4 ++++
 src/df.c |   13 ++++++++++++-
 2 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/NEWS b/NEWS
index 9274645..520e946 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   df displayed the symlink's device rather than that for the device node.
   [This bug was present in "the beginning".]
 
+  df now processes disk device nodes correctly in the presence of bind mounts.
+  Now df shows the base mounted file system rather than the last one mounted.
+  [This bug was present in "the beginning".]
+
   install now removes the target file if the strip program failed for any
   reason.  Before, that file was left behind, sometimes even with wrong
   permissions.
diff --git a/src/df.c b/src/df.c
index 1d08869..e8c46f6 100644
--- a/src/df.c
+++ b/src/df.c
@@ -1062,10 +1062,21 @@ get_disk (char const *disk)
   if (resolved && resolved[0] == '/')
     disk = resolved;
 
+  size_t best_match_len = SIZE_MAX;
   for (me = mount_list; me; me = me->me_next)
     {
       if (STREQ (disk, me->me_devname))
-        best_match = me;
+        {
+          size_t len = strlen (me->me_mountdir);
+          if (len < best_match_len)
+            {
+              best_match = me;
+              if (len == 1) /* Traditional root.  */
+                break;
+              else
+                best_match_len = len;
+            }
+        }
     }
 
   free (resolved);
-- 
1.7.7.6

Reply via email to