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; }