summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2014-06-24 15:34:39 +0100
committerPádraig Brady <P@draigBrady.com>2014-06-25 09:55:12 +0100
commitd71c12f1e4e165c7da59989b49ded2805b7977cc (patch)
tree51dc1d73c2d81c7d28feddc6fe6c535fca829897 /src
parent828801a174de8fa6e492f311210c37394f13b30f (diff)
downloadcoreutils-d71c12f1e4e165c7da59989b49ded2805b7977cc.tar.xz
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
Diffstat (limited to 'src')
-rw-r--r--src/df.c42
1 files changed, 41 insertions, 1 deletions
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;
}