From d71c12f1e4e165c7da59989b49ded2805b7977cc Mon Sep 17 00:00:00 2001 From: Pádraig Brady Date: Tue, 24 Jun 2014 15:34:39 +0100 Subject: df: report correct device in presence of eclipsed mounts * src/df.c (last_device_for_mount): A new function to identify the last device mounted for a mount point. (get_disk): Use the above to discard mount entries for a device, where a later mount entry uses a different device name than that of the user specified device. * tests/df/over-mount-device.sh: A new root test. * tests/local.mk: Reference the new test. * NEWS: Reword for all these related recent fixes. Discussed at: http://bugs.gnu.org/16539#69 --- src/df.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'src/df.c') diff --git a/src/df.c b/src/df.c index dc6544bc6..063cabf30 100644 --- a/src/df.c +++ b/src/df.c @@ -1114,6 +1114,33 @@ get_dev (char const *disk, char const *mount_point, char const* file, 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 @@ -1122,6 +1149,7 @@ 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); @@ -1139,9 +1167,12 @@ get_disk (char const *disk) 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 (! best_match_accessible || len < best_match_len) + if (! eclipsed_device + && (! best_match_accessible || len < best_match_len)) { struct stat disk_stats; bool this_match_accessible = false; @@ -1159,6 +1190,8 @@ get_disk (char const *disk) best_match_len = len; } } + + free (last_device); } free (canon_dev); @@ -1173,6 +1206,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; } -- cgit v1.2.3-70-g09d2