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