From d71c12f1e4e165c7da59989b49ded2805b7977cc Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Tue, 24 Jun 2014 15:34:39 +0100
Subject: [PATCH] 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
---
NEWS | 9 +++---
src/df.c | 42 +++++++++++++++++++++++++-
tests/df/over-mount-device.sh | 57 +++++++++++++++++++++++++++++++++++
tests/local.mk | 1 +
4 files changed, 104 insertions(+), 5 deletions(-)
create mode 100755 tests/df/over-mount-device.sh
diff --git a/NEWS b/NEWS
index 090254d8ac..653278528d 100644
--- a/NEWS
+++ b/NEWS
@@ -44,10 +44,11 @@ GNU coreutils NEWS -*- outline -*-
[These dd bugs were present in "the beginning".]
- df now elides duplicates for virtual file systems like tmpfs.
- Displays the correct device details for points mounted multiple times.
- Displays placeholder values for inaccessible file systems,
- rather than error messages or values for the wrong file system.
+ df has more fixes related to the newer dynamic representation of file systems:
+ Duplicates are elided for virtual file systems like tmpfs.
+ Details for the correct device are output for points mounted multiple times.
+ Placeholder values are output for inaccessible file systems, rather than
+ than error messages or values for the wrong file system.
[These bugs were present in "the beginning".]
du now silently ignores directory cycles introduced with bind mounts.
diff --git a/src/df.c b/src/df.c
index dc6544bc6a..063cabf300 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;
}
diff --git a/tests/df/over-mount-device.sh b/tests/df/over-mount-device.sh
new file mode 100755
index 0000000000..a85ce8dbf7
--- /dev/null
+++ b/tests/df/over-mount-device.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Ensure that df /dev/loop0 errors out if overmounted by another device
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see