diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | src/df.c | 31 | ||||
-rwxr-xr-x | tests/df/skip-duplicates.sh | 47 |
3 files changed, 50 insertions, 30 deletions
@@ -44,6 +44,8 @@ GNU coreutils NEWS -*- outline -*- [These dd bugs were present in "the beginning".] + df now correctly elides duplicates for virtual file systems like tmpfs. + head --bytes=-N and --lines=-N now handles devices more consistently, not ignoring data from virtual devices like /dev/zero, or on BSD systems data from tty devices. @@ -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; } } } diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh index 266520aa6..d872f27fc 100755 --- a/tests/df/skip-duplicates.sh +++ b/tests/df/skip-duplicates.sh @@ -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 <stdio.h> #include <stdlib.h> +#include <string.h> #include <mntent.h> +#define STREQ(a, b) (strcmp (a, b) == 0) + struct mntent *getmntent (FILE *fp) { + static char *nonroot_fs; + static int done; + /* Prove that LD_PRELOAD works. */ - static int done = 0; if (!done) { fclose (fopen ("x", "w")); @@ -43,18 +52,30 @@ struct mntent *getmntent (FILE *fp) static struct mntent mntents[] = { {.mnt_fsname="/short", .mnt_dir="/invalid/mount/dir"}, {.mnt_fsname="fsname", .mnt_dir="/",}, - {.mnt_fsname="/fsname", .mnt_dir="/root"}, + {.mnt_fsname="/fsname", .mnt_dir="/."}, {.mnt_fsname="/fsname", .mnt_dir="/"}, + {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"}, + {.mnt_fsname="virtfs", .mnt_dir="/NONROOT"}, }; - if (!getenv ("CU_TEST_DUPE_INVALID") && done == 1) + if (done == 1) + { + nonroot_fs = getenv ("CU_NONROOT_FS"); + if (!nonroot_fs || !*nonroot_fs) + nonroot_fs = "/"; /* merge into / entries. */ + } + + if (done == 1 && !getenv ("CU_TEST_DUPE_INVALID")) done++; /* skip the first entry. */ - while (done++ <= 4) + while (done++ <= 6) { mntents[done-2].mnt_type = "-"; + if (STREQ (mntents[done-2].mnt_dir, "/NONROOT")) + mntents[done-2].mnt_dir = nonroot_fs; return &mntents[done-2]; } + return NULL; } EOF @@ -69,22 +90,22 @@ 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 one entry. +# consist of a header and unique entries. LD_PRELOAD=./k.so df >out || fail=1 -test $(wc -l <out) -eq 2 || { fail=1; cat out; } +test $(wc -l <out) -eq $(expr 1 + $unique_entries) || { fail=1; cat out; } # Ensure we fail when unable to stat invalid entries LD_PRELOAD=./k.so CU_TEST_DUPE_INVALID=1 df >out && fail=1 -test $(wc -l <out) -eq 2 || { fail=1; cat out; } +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 '/root' -test $(grep -c '/root' <out) -eq 0 || { fail=1; cat out; } +# ... and "/fsname" with '/' as Mounted on over '/.' +test $(grep -cF '/.' <out) -eq 0 || { fail=1; cat out; } # Ensure that filtering duplicates does not affect -a processing. LD_PRELOAD=./k.so df -a >out || fail=1 -test $(wc -l <out) -eq 4 || { fail=1; cat out; } +test $(wc -l <out) -eq 6 || { fail=1; cat out; } # Ensure that filtering duplicates does not affect # argument processing (now without the fake getmntent()). |