>From decfe8df670818aa36637470bc38f221d49704b7 Mon Sep 17 00:00:00 2001 From: Ondrej Oprala Date: Thu, 24 Jan 2013 17:28:54 +0100 Subject: [PATCH] df: prefer fullpath entries when deduplicating * src/df.c (struct devlist): Add a new element for storing pointers to mount_entry structures. (dev_approved): Check if a device is in the global devlist. (dev_examine): Renamed from dev_examined, the function now favors entries with a '/' character in me_devname or those with the shortest me_mountdir string, if multiple entries fulfill the first condition. (get_all_entries): Call dev_examine and dev_approved if appropriate. (get_dev): Do not call dev_examined. * tests/df/skip-duplicates.sh: Add tests. --- src/df.c | 45 +++++++++++++++++++++++++++++++++++++-------- tests/df/skip-duplicates.sh | 18 ++++++++++++++---- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/df.c b/src/df.c index 9523cc1..89bc93f 100644 --- a/src/df.c +++ b/src/df.c @@ -48,6 +48,7 @@ struct devlist { dev_t dev_num; + struct mount_entry *me; struct devlist *next; }; @@ -609,24 +610,44 @@ excluded_fstype (const char *fstype) /* Check if the device was already examined. */ static bool -dev_examined (char const *mount_dir, char const *devname) +dev_approved (const struct mount_entry *me) +{ + struct devlist *devlist = devlist_head; + for ( ; devlist; devlist = devlist->next) + if (devlist->me == me) + return true; + + return false; +} + +static int +dev_examine (struct mount_entry *me) { struct stat buf; - if (-1 == stat (mount_dir, &buf)) - return false; + if (-1 == stat (me->me_mountdir, &buf)) + return -1; struct devlist *devlist = devlist_head; for ( ; devlist; devlist = devlist->next) if (devlist->dev_num == buf.st_dev) - return true; + { + if ((!strchr (devlist->me->me_devname, '/') + && strchr (me->me_devname, '/')) + || (strchr (devlist->me->me_devname, '/') + && strchr (me->me_devname, '/') + && strlen (devlist->me->me_mountdir) > strlen (me->me_mountdir))) + devlist->me = me; + + return 0; + } /* Add the device number to the global list devlist. */ devlist = xmalloc (sizeof *devlist); + devlist->me = me; devlist->dev_num = buf.st_dev; devlist->next = devlist_head; devlist_head = devlist; - - return false; + return 0; } /* Return true if N is a known integer value. On many file systems, @@ -803,8 +824,6 @@ get_dev (char const *disk, char const *mount_point, /* No arguments nor "df -a", then check if df has to ... */ if (!show_rootfs && STREQ (disk, ROOTFS)) return; /* ... skip rootfs: (unless -trootfs is given. */ - if (dev_examined (mount_point, disk)) - return; /* ... skip duplicate entries (bind mounts). */ } /* If MOUNT_POINT is NULL, then the file system is not mounted, and this @@ -1133,9 +1152,19 @@ get_all_entries (void) { struct mount_entry *me; + if (!show_rootfs && !show_all_fs && !show_listed_fs) + { + for (me = mount_list; me; me = me->me_next) + dev_examine (me); + } + for (me = mount_list; me; me = me->me_next) + { + if (!show_rootfs && !show_all_fs && !show_listed_fs && !dev_approved (me)) + continue; get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type, me->me_dummy, me->me_remote, NULL, true); + } } /* Add FSTYPE to the list of file system types to display. */ diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh index 31ab014..20f3910 100755 --- a/tests/df/skip-duplicates.sh +++ b/tests/df/skip-duplicates.sh @@ -39,10 +39,15 @@ struct mntent *getmntent (FILE *fp) static struct mntent mntent; - while (done++ < 3) + while (done++ < 4) { - mntent.mnt_fsname = "fsname"; - mntent.mnt_dir = "/"; + /* File system - Mounted on + fsname / + /fsname /root + /fsname / + */ + mntent.mnt_fsname = (done == 2) ? "fsname" : "/fsname"; + mntent.mnt_dir = (done == 3) ? "/root" : "/"; mntent.mnt_type = "-"; return &mntent; @@ -65,9 +70,14 @@ test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?" LD_PRELOAD=./k.so df >out || fail=1 test $(wc -l out || fail=1 -test $(wc -l