summaryrefslogtreecommitdiff
path: root/src/df.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2004-05-04 07:26:33 +0000
committerJim Meyering <jim@meyering.net>2004-05-04 07:26:33 +0000
commit3145fdd1eda17c7a24d7561cdeecacef2268d34b (patch)
tree6e46ab1bfb9157c78dc521ad6aaf9690ca360bc2 /src/df.c
parentb9c20c62fba9fa0ccfc80eaee99eec450f15e950 (diff)
downloadcoreutils-3145fdd1eda17c7a24d7561cdeecacef2268d34b.tar.xz
(show_disk, show_point): If several filesystems are
mounted on the same mount point, prefer the last one, not the first. Problem reported by Christian Jones in <http://mail.gnu.org/archive/html/bug-coreutils/2004-04/msg00200.html>. (show_disk): Remove unused statp arg. Return bool, not int. (show_point): Rewrite to avoid gotos. Use the same algorithm for lofs and dummies for each pass through the mount table, rather than subtly different algorithms (which are probably inadvertent).
Diffstat (limited to 'src/df.c')
-rw-r--r--src/df.c195
1 files changed, 91 insertions, 104 deletions
diff --git a/src/df.c b/src/df.c
index e348f3253..40af13603 100644
--- a/src/df.c
+++ b/src/df.c
@@ -521,22 +521,26 @@ done:
}
/* If DISK corresponds to a mount point, show its usage
- and return nonzero. Otherwise, return zero.
- STATP must be the result of `stat (DISK, STATP)'. */
-static int
-show_disk (const char *disk, const struct stat *statp)
+ and return true. Otherwise, return false. */
+static bool
+show_disk (char const *disk)
{
- struct mount_entry *me;
+ struct mount_entry const *me;
+ struct mount_entry const *best_match = NULL;
for (me = mount_list; me; me = me->me_next)
if (STREQ (disk, me->me_devname))
- {
- show_dev (me->me_devname, me->me_mountdir, me->me_type,
- me->me_dummy, me->me_remote);
- return 1;
- }
+ best_match = me;
- return 0;
+ if (best_match)
+ {
+ show_dev (best_match->me_devname, best_match->me_mountdir,
+ best_match->me_type, best_match->me_dummy,
+ best_match->me_remote);
+ return true;
+ }
+
+ return false;
}
/* Figure out which device file or directory POINT is mounted on
@@ -547,121 +551,104 @@ show_point (const char *point, const struct stat *statp)
{
struct stat disk_stats;
struct mount_entry *me;
- struct mount_entry *matching_dummy = NULL;
+ struct mount_entry const *best_match = NULL;
/* If POINT is an absolute path name, see if we can find the
mount point without performing any extra stat calls at all. */
if (*point == '/')
{
- for (me = mount_list; me; me = me->me_next)
- {
- if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs"))
- {
- /* Prefer non-dummy entries. */
- if (! me->me_dummy)
- goto show_me;
- matching_dummy = me;
- }
- }
+ /* Find the best match: prefer non-dummies, and then prefer the
+ last match if there are ties. */
- if (matching_dummy)
- goto show_matching_dummy;
+ for (me = mount_list; me; me = me->me_next)
+ if (STREQ (me->me_mountdir, point) && !STREQ (me->me_type, "lofs")
+ && (!best_match || best_match->me_dummy || !me->me_dummy))
+ best_match = me;
}
/* Calculate the real absolute path for POINT, and use that to find
the mount point. This avoids statting unavailable mount points,
which can hang df. */
- {
- char *resolved = canonicalize_file_name (point);
- ssize_t resolved_len = resolved ? strlen (resolved) : -1;
- struct mount_entry *best_match = NULL;
+ if (! best_match)
+ {
+ char *resolved = canonicalize_file_name (point);
+ ssize_t resolved_len = resolved ? strlen (resolved) : -1;
- if (1 <= resolved_len && resolved[0] == '/')
- {
- size_t best_match_len = 0;
+ if (1 <= resolved_len && resolved[0] == '/')
+ {
+ size_t best_match_len = 0;
- for (me = mount_list; me; me = me->me_next)
- if (! me->me_dummy)
- {
- size_t len = strlen (me->me_mountdir);
- if (best_match_len < len && len <= resolved_len
- && (len == 1 /* root file system */
- || ((len == resolved_len || resolved[len] == '/')
- && strncmp (me->me_mountdir, resolved, len) == 0)))
- {
- best_match = me;
- best_match_len = len;
- }
- }
- }
+ for (me = mount_list; me; me = me->me_next)
+ if (!STREQ (me->me_type, "lofs")
+ && (!best_match || best_match->me_dummy || !me->me_dummy))
+ {
+ size_t len = strlen (me->me_mountdir);
+ if (best_match_len <= len && len <= resolved_len
+ && (len == 1 /* root file system */
+ || ((len == resolved_len || resolved[len] == '/')
+ && strncmp (me->me_mountdir, resolved, len) == 0)))
+ {
+ best_match = me;
+ best_match_len = len;
+ }
+ }
+ }
- if (resolved)
- free (resolved);
+ if (resolved)
+ free (resolved);
- if (best_match && !STREQ (best_match->me_type, "lofs")
- && stat (best_match->me_mountdir, &disk_stats) == 0
- && disk_stats.st_dev == statp->st_dev)
+ if (best_match
+ && (stat (best_match->me_mountdir, &disk_stats) != 0
+ || disk_stats.st_dev != statp->st_dev))
+ best_match = NULL;
+ }
+
+ if (! best_match)
+ for (me = mount_list; me; me = me->me_next)
{
- me = best_match;
- goto show_me;
+ if (me->me_dev == (dev_t) -1)
+ {
+ if (stat (me->me_mountdir, &disk_stats) == 0)
+ me->me_dev = disk_stats.st_dev;
+ else
+ {
+ error (0, errno, "%s", quote (me->me_mountdir));
+ exit_status = 1;
+ /* So we won't try and fail repeatedly. */
+ me->me_dev = (dev_t) -2;
+ }
+ }
+
+ if (statp->st_dev == me->me_dev
+ && !STREQ (me->me_type, "lofs")
+ && (!best_match || best_match->me_dummy || !me->me_dummy))
+ {
+ /* Skip bogus mtab entries. */
+ if (stat (me->me_mountdir, &disk_stats) != 0
+ || disk_stats.st_dev != me->me_dev)
+ me->me_dev = (dev_t) -2;
+ else
+ best_match = me;
+ }
}
- }
- for (me = mount_list; me; me = me->me_next)
+ if (best_match)
+ show_dev (best_match->me_devname, best_match->me_mountdir,
+ best_match->me_type, best_match->me_dummy, best_match->me_remote);
+ else
{
- if (me->me_dev == (dev_t) -1)
- {
- if (stat (me->me_mountdir, &disk_stats) == 0)
- me->me_dev = disk_stats.st_dev;
- else
- {
- error (0, errno, "%s", quote (me->me_mountdir));
- exit_status = 1;
- /* So we won't try and fail repeatedly. */
- me->me_dev = (dev_t) -2;
- }
- }
+ /* We couldn't find the mount entry corresponding to POINT. Go ahead and
+ print as much info as we can; methods that require the device to be
+ present will fail at a later point. */
- if (statp->st_dev == me->me_dev)
+ /* Find the actual mount point. */
+ char *mp = find_mount_point (point, statp);
+ if (mp)
{
- /* Skip bogus mtab entries. */
- if (stat (me->me_mountdir, &disk_stats) != 0
- || disk_stats.st_dev != me->me_dev)
- {
- me->me_dev = (dev_t) -2;
- continue;
- }
-
- /* Prefer non-dummy entries. */
- if (! me->me_dummy)
- goto show_me;
- matching_dummy = me;
+ show_dev (0, mp, 0, 0, 0);
+ free (mp);
}
}
-
- if (matching_dummy)
- goto show_matching_dummy;
-
- /* We couldn't find the mount entry corresponding to POINT. Go ahead and
- print as much info as we can; methods that require the device to be
- present will fail at a later point. */
- {
- /* Find the actual mount point. */
- char *mp = find_mount_point (point, statp);
- if (mp)
- {
- show_dev (0, mp, 0, 0, 0);
- free (mp);
- }
- }
-
- return;
-
- show_matching_dummy:
- me = matching_dummy;
- show_me:
- show_dev (me->me_devname, me->me_mountdir, me->me_type, me->me_dummy,
- me->me_remote);
}
/* Determine what kind of node PATH is and show the disk usage
@@ -671,7 +658,7 @@ static void
show_entry (const char *path, const struct stat *statp)
{
if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
- && show_disk (path, statp))
+ && show_disk (path))
return;
show_point (path, statp);