740027
diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c
740027
--- coreutils-8.22-orig/src/df.c	2015-07-03 15:51:44.293116375 +0200
740027
+++ coreutils-8.22/src/df.c	2015-07-03 16:02:48.743390691 +0200
740027
@@ -1057,6 +1057,33 @@ get_dev (char const *disk, char const *m
740027
   free (dev_name);
740027
 }
740027
 
740027
+/* Scan the mount list returning the _last_ device found for MOUNT.
740027
+   NULL is returned if MOUNT not found.  The result is malloced.  */
740027
+static char *
740027
+last_device_for_mount (char const* mount)
740027
+{
740027
+  struct mount_entry const *me;
740027
+  struct mount_entry const *le = NULL;
740027
+
740027
+  for (me = mount_list; me; me = me->me_next)
740027
+    {
740027
+      if (STREQ (me->me_mountdir, mount))
740027
+        le = me;
740027
+    }
740027
+
740027
+  if (le)
740027
+    {
740027
+      char *devname = le->me_devname;
740027
+      char *canon_dev = canonicalize_file_name (devname);
740027
+      if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
740027
+        return canon_dev;
740027
+      free (canon_dev);
740027
+      return xstrdup (le->me_devname);
740027
+    }
740027
+  else
740027
+    return NULL;
740027
+}
740027
+
740027
 /* If DISK corresponds to a mount point, show its usage
740027
    and return true.  Otherwise, return false.  */
740027
 static bool
740027
@@ -1064,27 +1091,57 @@ get_disk (char const *disk)
740027
 {
740027
   struct mount_entry const *me;
740027
   struct mount_entry const *best_match = NULL;
740027
+  bool best_match_accessible = false;
740027
+  bool eclipsed_device = false;
740027
   char const *file = disk;
740027
 
740027
   char *resolved = canonicalize_file_name (disk);
740027
-  if (resolved && resolved[0] == '/')
740027
+  if (resolved && IS_ABSOLUTE_FILE_NAME (resolved))
740027
     disk = resolved;
740027
 
740027
   size_t best_match_len = SIZE_MAX;
740027
   for (me = mount_list; me; me = me->me_next)
740027
     {
740027
-      if (STREQ (disk, me->me_devname))
740027
+      /* TODO: Should cache canon_dev in the mount_entry struct.  */
740027
+      char *devname = me->me_devname;
740027
+      char *canon_dev = canonicalize_file_name (me->me_devname);
740027
+      if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev))
740027
+        devname = canon_dev;
740027
+
740027
+      if (STREQ (disk, devname))
740027
         {
740027
+          char *last_device = last_device_for_mount (me->me_mountdir);
740027
+          eclipsed_device = last_device && ! STREQ (last_device, devname);
740027
           size_t len = strlen (me->me_mountdir);
740027
-          if (len < best_match_len)
740027
+
740027
+          if (! eclipsed_device
740027
+              && (! best_match_accessible || len < best_match_len))
740027
             {
740027
-              best_match = me;
740027
-              if (len == 1) /* Traditional root.  */
740027
-                break;
740027
-              else
740027
-                best_match_len = len;
740027
+              struct stat disk_stats;
740027
+              bool this_match_accessible = false;
740027
+
740027
+              if (stat (me->me_mountdir, &disk_stats) == 0)
740027
+                best_match_accessible = this_match_accessible = true;
740027
+
740027
+              if (this_match_accessible
740027
+                  || (! best_match_accessible && len < best_match_len))
740027
+                {
740027
+                  best_match = me;
740027
+                  if (len == 1) /* Traditional root.  */
740027
+                    {
740027
+                      free (last_device);
740027
+                      free (canon_dev);
740027
+                      break;
740027
+                    }
740027
+                  else
740027
+                    best_match_len = len;
740027
+                }
740027
             }
740027
+
740027
+          free (last_device);
740027
         }
740027
+
740027
+      free (canon_dev);
740027
     }
740027
 
740027
   free (resolved);
740027
@@ -1096,6 +1153,13 @@ get_disk (char const *disk)
740027
                best_match->me_remote, NULL, false);
740027
       return true;
740027
     }
740027
+  else if (eclipsed_device)
740027
+    {
740027
+      error (0, 0, _("cannot access %s: over-mounted by another device"),
740027
+             quote (file));
740027
+      exit_status = EXIT_FAILURE;
740027
+      return true;
740027
+    }
740027
 
740027
   return false;
740027
 }