>From 47c314a266042fd52890019fe3a7f0b5403c7e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?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 15846b0..f4204cb 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".] head --bytes=-N and --lines=-N now handles devices more diff --git a/src/df.c b/src/df.c index dc6544b..25a6df5 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 = ! 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 0000000..a85ce8d --- /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 . + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ df +require_root_ + +cwd=$(pwd) +cleanup_() { cd /; umount "$cwd/mnt"; umount "$cwd/mnt"; } + +skip=0 + +# Create 2 file systems +for i in 1 2; do + dd if=/dev/zero of=blob$i bs=8192 count=200 > /dev/null 2>&1 \ + || skip=1 + mkfs -t ext2 -F blob$i \ + || skip_ "failed to create ext2 file system" +done + +# Mount both at the same place (eclipsing the first) +mkdir mnt || skip=1 +mount -oloop blob1 mnt || skip=1 +eclipsed_dev=$(df --o=source mnt | tail -n1) || skip=1 +mount -oloop blob2 mnt || skip=1 + +test $skip = 1 \ + && skip_ "insufficient mount/ext2 support" + +df . || skip_ "failed to lookup the device for the current dir" + +echo "df: cannot access '$eclipsed_dev': over-mounted by another device" > exp + +# We should get an error for the eclipsed device and continue +df $eclipsed_dev . > out 2> err && fail=1 + +# header and single entry in output +test $(wc -l < out) = 2 || fail=1 + +compare exp err || fail=1 + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk index cd7da5b..86050dc 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -115,6 +115,7 @@ all_root_tests = \ tests/cp/sparse-fiemap.sh \ tests/dd/skip-seek-past-dev.sh \ tests/df/problematic-chars.sh \ + tests/df/over-mount-device.sh \ tests/du/bind-mount-dir-cycle.sh \ tests/id/setgid.sh \ tests/install/install-C-root.sh \ -- 1.7.7.6