summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--src/df.c22
-rwxr-xr-xtests/df/skip-duplicates.sh13
3 files changed, 31 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index 9679b4684..3919b7245 100644
--- a/NEWS
+++ b/NEWS
@@ -44,7 +44,9 @@ GNU coreutils NEWS -*- outline -*-
[These dd bugs were present in "the beginning".]
- 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".]
head --bytes=-N and --lines=-N now handles devices more
consistently, not ignoring data from virtual devices like /dev/zero,
diff --git a/src/df.c b/src/df.c
index 01ecca6c5..82b0c5f37 100644
--- a/src/df.c
+++ b/src/df.c
@@ -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);
+ }
+ }
+
}
}
diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh
index 44f7d4ca7..6fb6ff561 100755
--- a/tests/df/skip-duplicates.sh
+++ b/tests/df/skip-duplicates.sh
@@ -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 df >out && fail=1
test $(wc -l <out) -eq $(expr 1 + $unique_entries) || { fail=1; cat out; }
# df should also prefer "/fsname" over "fsname"
-test $(grep -c '/fsname' <out) -eq 1 || { fail=1; cat out; }
-# ... and "/fsname" with '/' as Mounted on over '/.'
-test $(grep -cF '/.' <out) -eq 0 || { fail=1; cat out; }
+if test "$unique_entries" = 2; then
+ test $(grep -c '/fsname' <out) -eq 1 || { fail=1; cat out; }
+ # ... and "/fsname" with '/' as Mounted on over '/.'
+ test $(grep -cF '/.' <out) -eq 0 || { fail=1; cat out; }
+fi
+
+# df should use the last seen devname (mnt_fsname)
+test $(grep -c 'virtfs2' <out) -eq 1 || { fail=1; cat out; }
# Ensure that filtering duplicates does not affect -a processing.
LD_PRELOAD=./k.so df -a >out || fail=1