diff --git a/coreutils-also_deduplicate_virtual_file_systems.patch b/coreutils-also_deduplicate_virtual_file_systems.patch new file mode 100644 index 0000000..9a26d76 --- /dev/null +++ b/coreutils-also_deduplicate_virtual_file_systems.patch @@ -0,0 +1,186 @@ +commit 2dc5d044a88fd64e11e35886e78b54a4a9fc2b23 +Author: Pádraig Brady
+Date: Sat Jan 25 01:14:29 2014 +0000
+
+ df: also deduplicate virtual file systems
+
+ * src/df.c (filter_mountlist): Remove the constraint that
+ a '/' needs to be in the device name for a mount entry to
+ be considered for deduplication. Virtual file systems also
+ have storage associated with them (like tmpfs for example),
+ and thus need to be deduplicated since they will be shown
+ in the default df output and subject to --total processing also.
+ * test/df/skip-duplicates.sh: Add a test to ensure we deduplicate
+ all entries, even for virtual file systems. Also avoid possible
+ length operations on many remote file systems in the initial
+ check of df operation. Also avoid the assumption that "/root"
+ is on the same file system as "/".
+ * NEWS: Mention the change in behavior.
+
+---
+ NEWS | 6 ++++-
+ src/df.c | 31 +++++++++++++----------------
+ tests/df/skip-duplicates.sh | 47 +++++++++++++++++++++++++++++++-------------
+ 3 files changed, 53 insertions(+), 31 deletions(-)
+
+Index: coreutils-8.22/NEWS
+===================================================================
+--- coreutils-8.22.orig/NEWS 2014-07-25 23:59:19.944878976 +0200
++++ coreutils-8.22/NEWS 2014-07-26 00:00:28.937016455 +0200
+@@ -1,6 +1,10 @@
+ GNU coreutils NEWS -*- outline -*-
+
+-* Noteworthy changes in release 8.22 (2013-12-13) [stable]
++ Changes done after the release of 8.22
++
++ df now correctly elides duplicates for virtual file systems like tmpfs.
++
++ Noteworthy changes in release 8.22 (2013-12-13) [stable]
+
+ ** Bug fixes
+
+Index: coreutils-8.22/src/df.c
+===================================================================
+--- coreutils-8.22.orig/src/df.c 2014-07-25 23:59:19.938879051 +0200
++++ coreutils-8.22/src/df.c 2014-07-25 23:59:19.944878976 +0200
+@@ -630,26 +630,23 @@ filter_mount_list (void)
+ }
+ else
+ {
+- /* If the device name is a real path name ... */
+- if (strchr (me->me_devname, '/'))
++ /* If we've already seen this device... */
++ for (devlist = devlist_head; devlist; devlist = devlist->next)
++ if (devlist->dev_num == buf.st_dev)
++ break;
++
++ if (devlist)
+ {
+- /* ... try to find its device number in the devlist. */
+- for (devlist = devlist_head; devlist; devlist = devlist->next)
+- if (devlist->dev_num == buf.st_dev)
+- break;
++ discard_me = me;
+
+- if (devlist)
++ /* ...let the shorter mountdir win. */
++ if ((strchr (me->me_devname, '/')
++ && ! strchr (devlist->me->me_devname, '/'))
++ || (strlen (devlist->me->me_mountdir)
++ > strlen (me->me_mountdir)))
+ {
+- discard_me = me;
+-
+- /* Let the shorter mountdir win. */
+- if (! strchr (devlist->me->me_devname, '/')
+- || (strlen (devlist->me->me_mountdir)
+- > strlen (me->me_mountdir)))
+- {
+- discard_me = devlist->me;
+- devlist->me = me;
+- }
++ discard_me = devlist->me;
++ devlist->me = me;
+ }
+ }
+ }
+Index: coreutils-8.22/tests/df/skip-duplicates.sh
+===================================================================
+--- coreutils-8.22.orig/tests/df/skip-duplicates.sh 2013-12-04 15:48:30.000000000 +0100
++++ coreutils-8.22/tests/df/skip-duplicates.sh 2014-07-25 23:59:19.944878976 +0200
+@@ -21,19 +21,28 @@
+ print_ver_ df
+ require_gcc_shared_
+
+-df || skip_ "df fails"
++# We use --local here so as to not activate
++# potentially very many remote mounts.
++df --local || skip_ "df fails"
+
+-# Simulate an mtab file with two entries of the same device number.
+-# Also add entries with unstatable mount dirs to ensure that's handled.
++export CU_NONROOT_FS=$(df --local --output=target 2>&1 | grep /. | head -n1)
++test -z "$CU_NONROOT_FS" && unique_entries=1 || unique_entries=2
++
++# Simulate an mtab file to test various cases.
+ cat > k.c <<'EOF' || framework_failure_
+ #include
+Date: Mon May 12 15:46:43 2014 +0100
+
+ maint: avoid clang -Wtautological-constant-out-of-range-compare warning
+
+ * src/df.c (decode_output_arg): Use only enum constants to avoid
+ clang "warning: comparison of constant -1 with expression of
+ type 'display_field_t' is always false"
+
+diff --git a/src/df.c b/src/df.c
+index a7fc57f..01ecca6 100644
+--- a/src/df.c
++++ b/src/df.c
+@@ -144,7 +144,8 @@ typedef enum
+ IAVAIL_FIELD, /* inodes available */
+ IPCENT_FIELD, /* inodes used in percent */
+ TARGET_FIELD, /* mount point */
+- FILE_FIELD /* specified file name */
++ FILE_FIELD, /* specified file name */
++ INVALID_FIELD /* validation marker */
+ } display_field_t;
+
+ /* Flag if a field contains a block, an inode or another value. */
+@@ -372,7 +373,7 @@ decode_output_arg (char const *arg)
+ *comma++ = 0;
+
+ /* process S. */
+- display_field_t field = -1;
++ display_field_t field = INVALID_FIELD;
+ for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++)
+ {
+ if (STREQ (field_data[i].arg, s))
+@@ -381,7 +382,7 @@ decode_output_arg (char const *arg)
+ break;
+ }
+ }
+- if (field == -1)
++ if (field == INVALID_FIELD)
+ {
+ error (0, 0, _("option --output: field %s unknown"), quote (s));
+ usage (EXIT_FAILURE);
diff --git a/coreutils-avoid_compiler_warnings_with_some_assert_implementations.patch b/coreutils-avoid_compiler_warnings_with_some_assert_implementations.patch
new file mode 100644
index 0000000..bfead01
--- /dev/null
+++ b/coreutils-avoid_compiler_warnings_with_some_assert_implementations.patch
@@ -0,0 +1,35 @@
+commit 1239ac573df0a699d6999aed23caaf4a0eb099df
+Author: Ben Walton
+Date: Mon May 12 13:29:01 2014 +0100
+
+ df: fix handling of symlinks in mount list
+
+ The symlink handling in commit v8.21-172-g33660b4 was incomplete
+ in the case where there were symlinks in the mount list itself.
+ For example, in the case where /dev/mapper/fedora-home was in the
+ mount list and that in turn was a symlink to /dev/dm-2, we have:
+
+ before> df --out=source /dev/mapper/fedora-home
+ devtmpfs
+
+ after > df --out=source /dev/mapper/fedora-home
+ /dev/mapper/fedora-home
+
+ * src/df.c (get_disk): Compare canonicalized device names from
+ the mount list. Note we still display the non canonicalized name,
+ even if longer, as we assume that is the most representative.
+ * tests/df/df-symlink.sh: This could theoretically fail on some systems
+ depending on the content of the mount list, but adjust to fail on any
+ system where symlinks are present in the mount list for the current dir.
+
+diff --git a/src/df.c b/src/df.c
+index 2b5a54e..24897a3 100644
+--- a/src/df.c
++++ b/src/df.c
+@@ -1056,13 +1056,19 @@ get_disk (char const *disk)
+ 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))
+ {
+ size_t len = strlen (me->me_mountdir);
+ if (len < best_match_len)
+@@ -1074,6 +1080,8 @@ get_disk (char const *disk)
+ best_match_len = len;
+ }
+ }
++
++ free (canon_dev);
+ }
+
+ free (resolved);
+diff --git a/tests/df/df-symlink.sh b/tests/df/df-symlink.sh
+index aaed810..6d96bd2 100755
+--- a/tests/df/df-symlink.sh
++++ b/tests/df/df-symlink.sh
+@@ -28,4 +28,11 @@ df --out=source,target "$disk" > exp || skip_ "cannot get info for $disk"
+ df --out=source,target symlink > out || fail=1
+ compare exp out || fail=1
+
++# Ensure we output the same values for device nodes and '.'
++# This was not the case in coreutil-8.22 on systems
++# where the device in the mount list was a symlink itself.
++# I.E. '.' => /dev/mapper/fedora-home -> /dev/dm-2
++df --out=source,target '.' > out || fail=1
++compare exp out || fail=1
++
+ Exit $fail
diff --git a/coreutils-ignore_non_file_system_entries_in_proc_mounts.patch b/coreutils-ignore_non_file_system_entries_in_proc_mounts.patch
new file mode 100644
index 0000000..7216c2f
--- /dev/null
+++ b/coreutils-ignore_non_file_system_entries_in_proc_mounts.patch
@@ -0,0 +1,51 @@
+commit cbfb34c7d32e888b39e03a51a374ed664e9fa31b
+Author: Pádraig Brady
+Date: Mon May 12 14:49:13 2014 +0100
+
+ df: ignore non file system entries in /proc/mounts
+
+ Linux with network namespaces contains entries in /proc/mounts like:
+ proc net:[4026532464] proc rw,nosuid,nodev,noexec,relatime 0 0
+ resulting in a failure to stat 'net:[...]', inducing a warning
+ and an exit with failure status.
+
+ * src/df.c (get_dev): Ignore all relative mount points.
+ * tests/df/skip-duplicates.sh: Add an entry to test relative dirs.
+
+diff --git a/src/df.c b/src/df.c
+index 24897a3..a7fc57f 100644
+--- a/src/df.c
++++ b/src/df.c
+@@ -853,6 +853,11 @@ get_dev (char const *disk, char const *mount_point, char const* file,
+ if (!selected_fstype (fstype) || excluded_fstype (fstype))
+ return;
+
++ /* Ignore relative MOUNT_POINTs, which are present for example
++ in /proc/mounts on Linux with network namespaces. */
++ if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point))
++ return;
++
+ /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
+ program reports on the file system that the special file is on.
+ It would be better to report on the unmounted file system,
+diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh
+index d872f27..44f7d4c 100755
+--- a/tests/df/skip-duplicates.sh
++++ b/tests/df/skip-duplicates.sh
+@@ -56,6 +56,7 @@ struct mntent *getmntent (FILE *fp)
+ {.mnt_fsname="/fsname", .mnt_dir="/"},
+ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"},
+ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"},
++ {.mnt_fsname="netns", .mnt_dir="net:[1234567]"},
+ };
+
+ if (done == 1)
+@@ -68,7 +69,7 @@ struct mntent *getmntent (FILE *fp)
+ if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID"))
+ done++; /* skip the first entry. */
+
+- while (done++ <= 6)
++ while (done++ <= 7)
+ {
+ mntents[done-2].mnt_type = "-";
+ if (STREQ (mntents[done-2].mnt_dir, "/NONROOT"))
diff --git a/coreutils-improve_df_--human_and_--si,_help_and_man_page.patch b/coreutils-improve_df_--human_and_--si,_help_and_man_page.patch
new file mode 100644
index 0000000..6b5a4dd
--- /dev/null
+++ b/coreutils-improve_df_--human_and_--si,_help_and_man_page.patch
@@ -0,0 +1,53 @@
+commit 849c1c5b16c32756e14be719855601017770e621
+Author: Pádraig Brady
+Date: Mon Mar 3 02:49:25 2014 +0000
+
+ doc: improve df --human and --si, help and man page
+
+ * src/df.c (usage): Adjust the --human and --si descriptions
+ to not depend on each other. Also include an example that is
+ illustrative of the rounding, suffix, width, and localized fractions.
+ * src/system.h (emit_size_note). Adjust so that it's obvious the
+ description is pertaining to the input SIZE argument, and not
+ to any sizes that might be output by df for example.
+ Fixes http://bugs.gnu.org/16922
+
+diff --git a/src/df.c b/src/df.c
+index e4fafb9..3036c74 100644
+--- a/src/df.c
++++ b/src/df.c
+@@ -1260,15 +1260,16 @@ or all file systems by default.\n\
+
+ emit_mandatory_arg_note ();
+
++ /* TRANSLATORS: The thousands and decimal separators are best
++ adjusted to an appropriate default for your locale. */
+ fputs (_("\
+ -a, --all include dummy file systems\n\
+ -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\
+ '-BM' prints sizes in units of 1,048,576 bytes;\n\
+ see SIZE format below\n\
+ --total produce a grand total\n\
+- -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\
+-\n\
+- -H, --si likewise, but use powers of 1000 not 1024\n\
++ -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\
++ -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\
+ "), stdout);
+ fputs (_("\
+ -i, --inodes list inode information instead of block usage\n\
+diff --git a/src/system.h b/src/system.h
+index 39750e8..a9588e7 100644
+--- a/src/system.h
++++ b/src/system.h
+@@ -549,8 +549,8 @@ static inline void
+ emit_size_note (void)
+ {
+ fputs (_("\n\
+-SIZE is an integer and optional unit (example: 10M is 10*1024*1024). Units\n\
+-are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB, ... (powers of 1000).\n\
++The SIZE argument is an integer and optional unit (example: 10K is 10*1024).\n\
++Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers of 1000).\n\
+ "), stdout);
+ }
+
diff --git a/coreutils-look_for_accessible_mount_points_for_specified_devices.patch b/coreutils-look_for_accessible_mount_points_for_specified_devices.patch
new file mode 100644
index 0000000..3eee8e1
--- /dev/null
+++ b/coreutils-look_for_accessible_mount_points_for_specified_devices.patch
@@ -0,0 +1,55 @@
+commit 828801a174de8fa6e492f311210c37394f13b30f
+Author: Pádraig Brady
+Date: Wed Jun 18 13:10:17 2014 +0100
+
+ df: look for accessible mount points for specified devices
+
+ * src/df.c (get_disk): Include whether we can access the mount dir,
+ in the mount entry selection criteria. This handles the case where
+ a device is (bind) mounted multiple times with the shortest mount path
+ not being accessible, while some of the other mount points are.
+ Discussed at: http://bugs.gnu.org/16539#63
+
+diff --git a/src/df.c b/src/df.c
+index d6d4b0e..dc6544b 100644
+--- a/src/df.c
++++ b/src/df.c
+@@ -1121,6 +1121,7 @@ get_disk (char const *disk)
+ {
+ struct mount_entry const *me;
+ struct mount_entry const *best_match = NULL;
++ bool best_match_accessible = false;
+ char const *file = disk;
+
+ char *resolved = canonicalize_file_name (disk);
+@@ -1139,13 +1140,24 @@ get_disk (char const *disk)
+ if (STREQ (disk, devname))
+ {
+ size_t len = strlen (me->me_mountdir);
+- if (len < best_match_len)
++
++ if (! 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. */
++ break;
++ else
++ best_match_len = len;
++ }
+ }
+ }
+
diff --git a/coreutils-output_placeholder_values_for_inaccessible_mount_points.patch b/coreutils-output_placeholder_values_for_inaccessible_mount_points.patch
new file mode 100644
index 0000000..2f1ec01
--- /dev/null
+++ b/coreutils-output_placeholder_values_for_inaccessible_mount_points.patch
@@ -0,0 +1,258 @@
+commit 9d736f8dbfef2b33d431dccf852dace9cfc84d59
+Author: Pádraig Brady
+Date: Wed Jun 4 00:09:11 2014 +0100
+
+ df: output placeholder values for inaccessible mount points
+
+ A system provided mount entry may be unavailable due to TOCTOU race,
+ or if another device has been over-mounted at that position, or due to
+ access permissions. In all these cases output "-" placeholder values
+ rather than either producing an error, or in the over-mount case
+ outputting values for the wrong device.
+
+ * src/df.c (device_list): A new global list now updated by
+ filter_mount_list().
+ (filter_mount_list): Adjust to take a parameter as to whether
+ update the global mount list, or only the mount <-> device ID mapping.
+ (get_dev): Use the device ID mapping to ensure we're not outputting
+ stats for the wrong device. Also output placeholder values when we
+ can't access a system specified mount point.
+ (get_all_entries): Set the DEVICE_ONLY param for filter_mount_list().
+ (devname_for_dev): A new function to search the mount <-> dev mapping.
+ * test/df/skip-duplicates.sh: Adjust accordingly.
+ * NEWS: Mention the bug fixes.
+
+ Discussed at: http://bugs.gnu.org/16539
+
+---
+ NEWS | 6 +-
+ src/df.c | 109 ++++++++++++++++++++++++++++++++------------
+ tests/df/skip-duplicates.sh | 6 +-
+ 3 files changed, 89 insertions(+), 32 deletions(-)
+
+Index: coreutils-8.22/NEWS
+===================================================================
+--- coreutils-8.22.orig/NEWS 2014-07-26 00:02:00.484871949 +0200
++++ coreutils-8.22/NEWS 2014-07-26 00:02:31.465484639 +0200
+@@ -2,8 +2,10 @@ GNU coreutils NEWS
+
+ Changes done after the release of 8.22
+
+- df now elides duplicates for virtual file systems like tmpfs, and will
+- display the correct device name for directories mounted multiple times.
++ 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.
+ [These bugs were present in "the beginning".]
+
+ Noteworthy changes in release 8.22 (2013-12-13) [stable]
+Index: coreutils-8.22/src/df.c
+===================================================================
+--- coreutils-8.22.orig/src/df.c 2014-07-26 00:02:00.468872150 +0200
++++ coreutils-8.22/src/df.c 2014-07-26 00:02:00.485871937 +0200
+@@ -45,12 +45,12 @@
+
+ /* Filled with device numbers of examined file systems to avoid
+ duplicities in output. */
+-struct devlist
++static struct devlist
+ {
+ dev_t dev_num;
+ struct mount_entry *me;
+ struct devlist *next;
+-};
++} *device_list;
+
+ /* If true, show even file systems with zero size or
+ uninteresting types. */
+@@ -607,23 +607,25 @@ excluded_fstype (const char *fstype)
+ In the case of duplicities - based on the device number - the mount entry
+ with a '/' in its me_devname (i.e. not pseudo name like tmpfs) wins.
+ If both have a real devname (e.g. bind mounts), then that with the shorter
+- me_mountdir wins. */
++ me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
++ the global device_list, rather than filtering the global mount_list. */
+
+ static void
+-filter_mount_list (void)
++filter_mount_list (bool devices_only)
+ {
+ struct mount_entry *me;
+
+- /* Store of already-processed device numbers. */
+- struct devlist *devlist_head = NULL;
+-
+- /* Sort all 'wanted' entries into the list devlist_head. */
++ /* Sort all 'wanted' entries into the list device_list. */
+ for (me = mount_list; me;)
+ {
+ struct stat buf;
+ struct devlist *devlist;
+ struct mount_entry *discard_me = NULL;
+
++ /* TODO: On Linux we might avoid this stat() and another in get_dev()
++ by using the device IDs available from /proc/self/mountinfo.
++ read_file_system_list() could populate me_dev from those
++ for efficiency and accuracy. */
+ if (-1 == stat (me->me_mountdir, &buf))
+ {
+ /* Stat failed - add ME to be able to complain about it later. */
+@@ -632,7 +634,7 @@ filter_mount_list (void)
+ else
+ {
+ /* If we've already seen this device... */
+- for (devlist = devlist_head; devlist; devlist = devlist->next)
++ for (devlist = device_list; devlist; devlist = devlist->next)
+ if (devlist->dev_num == buf.st_dev)
+ break;
+
+@@ -661,8 +663,9 @@ filter_mount_list (void)
+
+ if (discard_me)
+ {
+- me = me->me_next;
+- free_mount_entry (discard_me);
++ me = me->me_next;
++ if (! devices_only)
++ free_mount_entry (discard_me);
+ }
+ else
+ {
+@@ -670,26 +673,46 @@ filter_mount_list (void)
+ devlist = xmalloc (sizeof *devlist);
+ devlist->me = me;
+ devlist->dev_num = buf.st_dev;
+- devlist->next = devlist_head;
+- devlist_head = devlist;
++ devlist->next = device_list;
++ device_list = devlist;
+
+ me = me->me_next;
+ }
+ }
+
+ /* Finally rebuild the mount_list from the devlist. */
+- mount_list = NULL;
+- while (devlist_head)
++ if (! devices_only) {
++ mount_list = NULL;
++ while (device_list)
++ {
++ /* Add the mount entry. */
++ me = device_list->me;
++ me->me_next = mount_list;
++ mount_list = me;
++ /* Free devlist entry and advance. */
++ struct devlist *devlist = device_list->next;
++ free (device_list);
++ device_list = devlist;
++ }
++ }
++}
++
++/* Search a mount entry list for device id DEV.
++ Return the corresponding device name if found or NULL if not. */
++
++static char const * _GL_ATTRIBUTE_PURE
++devname_for_dev (dev_t dev)
++{
++ struct devlist *dl = device_list;
++
++ while (dl)
+ {
+- /* Add the mount entry. */
+- me = devlist_head->me;
+- me->me_next = mount_list;
+- mount_list = me;
+- /* Free devlist entry and advance. */
+- struct devlist *devlist = devlist_head->next;
+- free (devlist_head);
+- devlist_head = devlist;
++ if (dl->dev_num == dev)
++ return dl->me->me_devname;
++ dl = dl->next;
+ }
++
++ return NULL;
+ }
+
+ /* Return true if N is a known integer value. On many file systems,
+@@ -878,9 +901,40 @@ get_dev (char const *disk, char const *m
+ fsu = *force_fsu;
+ else if (get_fs_usage (stat_file, disk, &fsu))
+ {
+- error (0, errno, "%s", quote (stat_file));
+- exit_status = EXIT_FAILURE;
+- return;
++ /* If we can't access a system provided entry due
++ to it not being present (now), or due to permissions,
++ just output placeholder values rather than failing. */
++ if (process_all && (errno == EACCES || errno == ENOENT))
++ {
++ if (! show_all_fs)
++ return;
++
++ fstype = "-";
++ fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
++ fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
++ }
++ else
++ {
++ error (0, errno, "%s", quote (stat_file));
++ exit_status = EXIT_FAILURE;
++ return;
++ }
++ }
++ else if (process_all && show_all_fs)
++ {
++ /* Ensure we don't output incorrect stats for over-mounted directories.
++ Discard stats when the device name doesn't match. */
++ struct stat sb;
++ if (stat (stat_file, &sb) == 0)
++ {
++ char const * devname = devname_for_dev (sb.st_dev);
++ if (devname && ! STREQ (devname, disk))
++ {
++ fstype = "-";
++ fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree =
++ fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX;
++ }
++ }
+ }
+
+ if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
+@@ -1230,8 +1284,7 @@ get_all_entries (void)
+ {
+ struct mount_entry *me;
+
+- if (!show_all_fs)
+- filter_mount_list ();
++ filter_mount_list (show_all_fs);
+
+ for (me = mount_list; me; me = me->me_next)
+ get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type,
+Index: coreutils-8.22/tests/df/skip-duplicates.sh
+===================================================================
+--- coreutils-8.22.orig/tests/df/skip-duplicates.sh 2014-07-26 00:02:00.468872150 +0200
++++ coreutils-8.22/tests/df/skip-duplicates.sh 2014-07-26 00:02:00.485871937 +0200
+@@ -96,8 +96,8 @@ test -f x || skip_ "internal test failur
+ LD_PRELOAD=./k.so df -T >out || fail=1
+ test $(wc -l
+Date: Tue Jun 17 00:18:47 2014 +0100
+
+ df: use all of the last device details provided
+
+ * src/df.c (filter_mount_list): Recent commit v8.22-108-g25a2c94
+ failed to copy file system type along with the updated device name.
+ Therefore simply replace the existing mount entry with the
+ current one with all the latest device details. Note the name,
+ even if not shorter in this entry, will be replaced with a shorter
+ name in a subsequent mount entry.
+ * tests/df/skip-duplicates.sh: Add a test case.
+
+diff --git a/src/df.c b/src/df.c
+index 747d138..10047ce 100644
+--- a/src/df.c
++++ b/src/df.c
+@@ -642,7 +642,9 @@ filter_mount_list (void)
+ if ((strchr (me->me_devname, '/')
+ && ! strchr (devlist->me->me_devname, '/'))
+ || (strlen (devlist->me->me_mountdir)
+- > strlen (me->me_mountdir)))
++ > strlen (me->me_mountdir))
++ /* or one overmounted on a different device. */
++ || ! STREQ (devlist->me->me_devname, me->me_devname))
+ {
+ /* Discard mount entry for existing device. */
+ discard_me = devlist->me;
+@@ -652,17 +654,6 @@ filter_mount_list (void)
+ {
+ /* Discard mount entry currently being processed. */
+ discard_me = me;
+-
+- /* We might still want the devname from this mount entry as
+- the dev_num might not correlate with st_dev if another
+- device is subsequently overmounted at mountdir, so honor
+- the order of the presented list and replace with the
+- latest devname encountered. */
+- if (! STREQ (devlist->me->me_devname, me->me_devname))
+- {
+- free (devlist->me->me_devname);
+- devlist->me->me_devname = xstrdup (me->me_devname);
+- }
+ }
+
+ }
+diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh
+index 6fb6ff5..a620e73 100755
+--- a/tests/df/skip-duplicates.sh
++++ b/tests/df/skip-duplicates.sh
+@@ -54,8 +54,8 @@ struct mntent *getmntent (FILE *fp)
+ {.mnt_fsname="fsname", .mnt_dir="/",},
+ {.mnt_fsname="/fsname", .mnt_dir="/."},
+ {.mnt_fsname="/fsname", .mnt_dir="/"},
+- {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"},
+- {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT"},
++ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT", .mnt_type="fstype1"},
++ {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT", .mnt_type="fstype2"},
+ {.mnt_fsname="netns", .mnt_dir="net:[1234567]"},
+ };
+
+@@ -71,7 +71,8 @@ struct mntent *getmntent (FILE *fp)
+
+ while (done++ <= 7)
+ {
+- mntents[done-2].mnt_type = "-";
++ if (!mntents[done-2].mnt_type)
++ mntents[done-2].mnt_type = "-";
+ if (STREQ (mntents[done-2].mnt_dir, "/NONROOT"))
+ mntents[done-2].mnt_dir = nonroot_fs;
+ return &mntents[done-2];
+@@ -92,11 +93,11 @@ test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+ # The fake mtab file should only contain entries
+ # having the same device number; thus the output should
+ # consist of a header and unique entries.
+-LD_PRELOAD=./k.so df >out || fail=1
++LD_PRELOAD=./k.so df -T >out || fail=1
+ test $(wc -l
+Date: Thu May 29 15:30:46 2014 +0100
+
+ df: use the last device name provided by the system
+
+ The device name reported for a particular mount entry
+ may no longer be valid if the mount point was subsequently
+ mounted on a different device. Therefore honor the order
+ of the mount list returned by the system and use the last
+ reported device name.
+
+ * src/df.c (filter_mount_list): When discarding the current
+ mount entry, ensure that a new device name is not also discarded.
+ * tests/df/skip-duplicates.sh: Add a test case. Also fix
+ a false failure in the edge case of a system with only a
+ single file system.
+ * NEWS: Mention the fix.
+
+---
+ NEWS | 4 +++-
+ src/df.c | 22 +++++++++++++++++++---
+ tests/df/skip-duplicates.sh | 13 +++++++++----
+ 3 files changed, 31 insertions(+), 8 deletions(-)
+
+Index: coreutils-8.22/NEWS
+===================================================================
+--- coreutils-8.22.orig/NEWS 2014-07-26 00:00:59.716631657 +0200
++++ coreutils-8.22/NEWS 2014-07-26 00:01:35.008190452 +0200
+@@ -2,7 +2,9 @@ GNU coreutils NEWS
+
+ Changes done after the release of 8.22
+
+- df now correctly elides duplicates for virtual file systems like tmpfs.
++ df now elides duplicates for virtual file systems like tmpfs, and will
++ display the correct device name for directories mounted multiple times.
++ [These bugs were present in "the beginning".]
+
+ Noteworthy changes in release 8.22 (2013-12-13) [stable]
+
+Index: coreutils-8.22/src/df.c
+===================================================================
+--- coreutils-8.22.orig/src/df.c 2014-07-26 00:00:59.711631720 +0200
++++ coreutils-8.22/src/df.c 2014-07-26 00:00:59.716631657 +0200
+@@ -604,7 +604,7 @@ excluded_fstype (const char *fstype)
+ }
+
+ /* Filter mount list by skipping duplicate entries.
+- In the case of duplicities - based on to the device number - the mount entry
++ In the case of duplicities - based on the device number - the mount entry
+ with a '/' in its me_devname (i.e. not pseudo name like tmpfs) wins.
+ If both have a real devname (e.g. bind mounts), then that with the shorter
+ me_mountdir wins. */
+@@ -638,17 +638,33 @@ filter_mount_list (void)
+
+ if (devlist)
+ {
+- discard_me = me;
+-
+ /* ...let the shorter mountdir win. */
+ if ((strchr (me->me_devname, '/')
+ && ! strchr (devlist->me->me_devname, '/'))
+ || (strlen (devlist->me->me_mountdir)
+ > strlen (me->me_mountdir)))
+ {
++ /* Discard mount entry for existing device. */
+ discard_me = devlist->me;
+ devlist->me = me;
+ }
++ else
++ {
++ /* Discard mount entry currently being processed. */
++ discard_me = me;
++
++ /* We might still want the devname from this mount entry as
++ the dev_num might not correlate with st_dev if another
++ device is subsequently overmounted at mountdir, so honor
++ the order of the presented list and replace with the
++ latest devname encountered. */
++ if (! STREQ (devlist->me->me_devname, me->me_devname))
++ {
++ free (devlist->me->me_devname);
++ devlist->me->me_devname = xstrdup (me->me_devname);
++ }
++ }
++
+ }
+ }
+
+Index: coreutils-8.22/tests/df/skip-duplicates.sh
+===================================================================
+--- coreutils-8.22.orig/tests/df/skip-duplicates.sh 2014-07-26 00:00:59.706631782 +0200
++++ coreutils-8.22/tests/df/skip-duplicates.sh 2014-07-26 00:00:59.716631657 +0200
+@@ -55,7 +55,7 @@ struct mntent *getmntent (FILE *fp)
+ {.mnt_fsname="/fsname", .mnt_dir="/."},
+ {.mnt_fsname="/fsname", .mnt_dir="/"},
+ {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"},
+- {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"},
++ {.mnt_fsname="virtfs2", .mnt_dir="/NONROOT"},
+ {.mnt_fsname="netns", .mnt_dir="net:[1234567]"},
+ };
+
+@@ -100,9 +100,14 @@ LD_PRELOAD=./k.so CU_TEST_DUPE_INVALID=1
+ test $(wc -l