[coreutils/f16] fix showing duplicates in df (#709351, O.Oprala, B.Voelker), df: work around long-named /dev/disk/by

Ondrej Vasik ovasik at fedoraproject.org
Wed Dec 12 13:56:17 UTC 2012


commit 4e0606fb7ad457f20cb13328f298a9e5fd9bacdc
Author: Ondřej Vašík <ovasik at redhat.com>
Date:   Wed Dec 12 14:56:05 2012 +0100

    fix showing duplicates in df (#709351, O.Oprala, B.Voelker), df: work around long-named /dev/disk/by-uuid/... symlinks

 coreutils-8.17-df-duplicates.patch |  387 ++++++++++++++++++++++++++++++++++++
 coreutils-df-direct.patch          |    2 +-
 coreutils.spec                     |    8 +-
 3 files changed, 395 insertions(+), 2 deletions(-)
---
diff --git a/coreutils-8.17-df-duplicates.patch b/coreutils-8.17-df-duplicates.patch
new file mode 100644
index 0000000..20c258e
--- /dev/null
+++ b/coreutils-8.17-df-duplicates.patch
@@ -0,0 +1,387 @@
+diff -urNp coreutils-8.12-orig/doc/coreutils.texi coreutils-8.12/doc/coreutils.texi
+--- coreutils-8.12-orig/doc/coreutils.texi	2011-04-25 10:55:27.000000000 +0200
++++ coreutils-8.12/doc/coreutils.texi	2012-12-12 13:28:29.588025346 +0100
+@@ -10379,6 +10379,14 @@ Normally the disk space is printed in un
+ 1024 bytes, but this can be overridden (@pxref{Block size}).
+ Non-integer quantities are rounded up to the next higher unit.
+ 
++For bind mounts and without arguments, @command{df} only outputs the statistics
++for the first occurence of that device in the list of file systems (@var{mtab}),
++i.e., it hides duplicate entries, unless the @option{-a} option is specified.
++
++By default, @command{df} omits the early-boot pseudo file system type
++ at samp{rootfs}, unless the @option{-a} option is specified or that file system
++type is explicitly to be included by using the @option{-t} option.
++
+ @cindex disk device file
+ @cindex device file, disk
+ If an argument @var{file} is a disk device file containing a mounted
+diff -urNp coreutils-8.12-orig/src/df.c coreutils-8.12/src/df.c
+--- coreutils-8.12-orig/src/df.c	2011-04-25 11:45:49.000000000 +0200
++++ coreutils-8.12/src/df.c	2012-12-12 13:28:29.593156345 +0100
+@@ -25,6 +25,7 @@
+ #include <assert.h>
+ 
+ #include "system.h"
++#include "canonicalize.h"
+ #include "error.h"
+ #include "fsusage.h"
+ #include "human.h"
+@@ -45,6 +46,17 @@
+ /* If true, show inode information. */
+ static bool inode_format;
+ 
++/* Filled with device numbers of examined file systems to avoid
++   duplicities in output.  */
++struct devlist
++{
++  dev_t dev_num;
++  struct devlist *next;
++};
++
++/* Store of already-processed device numbers.  */
++static struct devlist *devlist_head;
++
+ /* If true, show even file systems with zero size or
+    uninteresting types. */
+ static bool show_all_fs;
+@@ -56,6 +68,12 @@ static bool show_local_fs;
+    command line argument -- even if it's a dummy (automounter) entry.  */
+ static bool show_listed_fs;
+ 
++/* If true, include rootfs in the output.  */
++static bool show_rootfs;
++
++/* The literal name of the initial root file system.  */
++static char const *ROOTFS = "rootfs";
++
+ /* Human-readable options for output.  */
+ static int human_output_opts;
+ 
+@@ -349,6 +367,29 @@ excluded_fstype (const char *fstype)
+   return false;
+ }
+ 
++/* Check if the device was already examined.  */
++
++static bool
++dev_examined (char const *mount_dir, char const *devname)
++{
++  struct stat buf;
++  if (-1 == stat (mount_dir, &buf))
++    return false;
++
++  struct devlist *devlist = devlist_head;
++  for ( ; devlist; devlist = devlist->next)
++    if (devlist->dev_num == buf.st_dev)
++      return true;
++
++  /* Add the device number to the global list devlist.  */
++  devlist = xmalloc (sizeof *devlist);
++  devlist->dev_num = buf.st_dev;
++  devlist->next = devlist_head;
++  devlist_head = devlist;
++
++  return false;
++}
++
+ /* Return true if N is a known integer value.  On many file systems,
+    UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
+    represents unknown.  Use a rule that works on AIX file systems, and
+@@ -417,6 +458,17 @@ add_uint_with_neg_flag (uintmax_t *dest,
+     *dest = -*dest;
+ }
+ 
++/* Return true if S ends in a string that may be a 36-byte UUID,
++   i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
++   each H is an upper or lower case hexadecimal digit.  */
++static bool _GL_ATTRIBUTE_PURE
++has_uuid_suffix (char const *s)
++{
++  size_t len = strlen (s);
++  return (36 < len
++          && strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
++}
++
+ /* Optain a space listing for the disk device with absolute file name DISK.
+    If MOUNT_POINT is non-NULL, it is the name of the root of the
+    file system on DISK.
+@@ -428,13 +480,16 @@ add_uint_with_neg_flag (uintmax_t *dest,
+    If FSTYPE is non-NULL, it is the type of the file system on DISK.
+    If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
+    not be able to produce statistics in this case.
+-   ME_DUMMY and ME_REMOTE are the mount entry flags.  */
++   ME_DUMMY and ME_REMOTE are the mount entry flags.
++   Caller must set PROCESS_ALL to true when iterating over all entries, as
++   when df is invoked with no non-option argument.  See below for details.  */
+ 
+ static void
+ get_dev (char const *disk, char const *mount_point,
+          char const *stat_file, char const *fstype,
+          bool me_dummy, bool me_remote,
+-         const struct fs_usage *force_fsu)
++         const struct fs_usage *force_fsu,
++         bool process_all)
+ {
+   struct fs_usage fsu;
+   char buf[LONGEST_HUMAN_READABLE + 2];
+@@ -459,6 +514,15 @@ get_dev (char const *disk, char const *m
+   if (!selected_fstype (fstype) || excluded_fstype (fstype))
+     return;
+ 
++  if (process_all && !show_all_fs && !show_listed_fs)
++    {
++      /* 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
+      program reports on the file system that the special file is on.
+      It would be better to report on the unmounted file system,
+@@ -488,6 +552,24 @@ get_dev (char const *disk, char const *m
+ 
+   if (! disk)
+     disk = "-";			/* unknown */
++
++  char *dev_name = xstrdup (disk);
++  char *resolved_dev;
++
++  /* On some systems, dev_name is a long-named symlink like
++     /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
++     much shorter and more useful name like /dev/sda1.  It may also look
++     like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
++     /dev/dm-0.  When process_all is true and dev_name is a symlink whose
++     name ends with a UUID use the resolved name instead.  */
++  if (process_all
++      && has_uuid_suffix (dev_name)
++      && (resolved_dev = canonicalize_filename_mode (dev_name, CAN_EXISTING)))
++    {
++      free (dev_name);
++      dev_name = resolved_dev;
++    }
++
+   if (! fstype)
+     fstype = "-";		/* unknown */
+ 
+@@ -537,7 +619,7 @@ get_dev (char const *disk, char const *m
+       switch (field)
+         {
+         case DEV_FIELD:
+-          cell = xstrdup (disk);
++          cell = dev_name;
+           break;
+ 
+         case TYPE_FIELD:
+@@ -648,7 +730,7 @@ get_disk (char const *disk)
+     {
+       get_dev (best_match->me_devname, best_match->me_mountdir, NULL,
+                best_match->me_type, best_match->me_dummy,
+-               best_match->me_remote, NULL);
++               best_match->me_remote, NULL, false);
+       return true;
+     }
+ 
+@@ -734,7 +816,7 @@ get_point (const char *point, const stru
+   if (best_match)
+     get_dev (best_match->me_devname, best_match->me_mountdir, point,
+              best_match->me_type, best_match->me_dummy, best_match->me_remote,
+-             NULL);
++             NULL, false);
+   else
+     {
+       /* We couldn't find the mount entry corresponding to POINT.  Go ahead and
+@@ -745,7 +827,7 @@ get_point (const char *point, const stru
+       char *mp = find_mount_point (point, statp);
+       if (mp)
+         {
+-          get_dev (NULL, mp, NULL, NULL, false, false, NULL);
++          get_dev (NULL, mp, NULL, NULL, false, false, NULL, false);
+           free (mp);
+         }
+     }
+@@ -774,7 +856,7 @@ get_all_entries (void)
+ 
+   for (me = mount_list; me; me = me->me_next)
+     get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
+-              me->me_dummy, me->me_remote, NULL);
++             me->me_dummy, me->me_remote, NULL, true);
+ }
+ 
+ /* Add FSTYPE to the list of file system types to display. */
+@@ -940,6 +1022,7 @@ main (int argc, char **argv)
+           /* Accept -F as a synonym for -t for compatibility with Solaris.  */
+         case 't':
+           add_fs_type (optarg);
++          show_rootfs = selected_fstype (ROOTFS);
+           break;
+ 
+         case 'v':		/* For SysV compatibility. */
+@@ -1066,13 +1149,21 @@ main (int argc, char **argv)
+     {
+       if (inode_format)
+         grand_fsu.fsu_blocks = 1;
+-      get_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu);
++      get_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu, false);
+     }
+ 
+   print_table ();
+ 
+   if (! file_systems_processed)
+     error (EXIT_FAILURE, 0, _("no file systems processed"));
++  IF_LINT (
++    while (devlist_head)
++      {
++        struct devlist *devlist = devlist_head->next;
++        free (devlist_head);
++        devlist_head = devlist;
++      }
++    );
+ 
+   exit (exit_status);
+ }
+diff -urNp coreutils-8.12-orig/tests/df/skip-duplicates coreutils-8.12/tests/df/skip-duplicates
+--- coreutils-8.12-orig/tests/df/skip-duplicates	1970-01-01 01:00:00.000000000 +0100
++++ coreutils-8.12/tests/df/skip-duplicates	2012-12-12 13:28:29.590144032 +0100
+@@ -0,0 +1,77 @@
++#!/bin/sh
++# Test df's behavior when the mount list contains duplicate entries.
++# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
++
++# Copyright (C) 2012 Free Software Foundation, Inc.
++
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++
++. "${srcdir=.}/init.sh"; path_prepend_ ../src
++print_ver_ df
++
++df || skip_ "df fails"
++
++# Simulate an mtab file with two entries of the same device number.
++cat > k.c <<'EOF' || framework_failure_
++#include <stdio.h>
++#include <mntent.h>
++
++struct mntent *getmntent (FILE *fp)
++{
++  /* Prove that LD_PRELOAD works. */
++  static int done = 0;
++  if (!done)
++    {
++      fclose (fopen ("x", "w"));
++      ++done;
++    }
++
++  static struct mntent mntent;
++
++  while (done++ < 3)
++    {
++      mntent.mnt_fsname = "fsname";
++      mntent.mnt_dir = "/";
++      mntent.mnt_type = "-";
++
++      return &mntent;
++    }
++  return NULL;
++}
++EOF
++
++# Then compile/link it:
++gcc --std=gnu99 -shared -fPIC -ldl -O2 k.c -o k.so \
++  || skip_ "getmntent hack does not work on this platform"
++
++# Test if LD_PRELOAD works:
++LD_PRELOAD=./k.so df
++test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
++
++# The fake mtab file should only contain 2 entries, both
++# having the same device number; thus the output should
++# consist of a header and one entry.
++LD_PRELOAD=./k.so df >out || fail=1
++test $(wc -l <out) -eq 2 || { 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 3 || { fail=1; cat out; }
++
++# Ensure that filtering duplcates does not affect
++# argument processing (now without the fake getmntent()).
++df '.' '.' >out || fail=1
++test $(wc -l <out) -eq 3 || { fail=1; cat out; }
++
++Exit $fail
+diff -urNp coreutils-8.12-orig/tests/df/skip-rootfs coreutils-8.12/tests/df/skip-rootfs
+--- coreutils-8.12-orig/tests/df/skip-rootfs	1970-01-01 01:00:00.000000000 +0100
++++ coreutils-8.12/tests/df/skip-rootfs	2012-12-12 13:28:29.591024467 +0100
+@@ -0,0 +1,46 @@
++#!/bin/sh
++# Test df's behavior for skipping the pseudo "rootfs" file system.
++
++# Copyright (C) 2012 Free Software Foundation, Inc.
++
++# This program is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++
++. "${srcdir=.}/init.sh"; path_prepend_ ../src
++print_ver_ df
++
++df || skip_ "df fails"
++
++# Verify that rootfs is in mtab (and shown when the -a option is specified).
++df -a >out || fail=1
++grep '^rootfs' out || skip_ "no rootfs in mtab"
++
++# Ensure that rootfs is supressed when no options is specified.
++df >out || fail=1
++grep '^rootfs' out && { fail=1; cat out; }
++
++# Ensure that the rootfs is shown when explicitly specifying "-t rootfs".
++df -t rootfs >out || fail=1
++grep '^rootfs' out || { fail=1; cat out; }
++
++# Ensure that the rootfs is shown when explicitly specifying "-t rootfs",
++# even when the -a option is specified.
++df -t rootfs -a >out || fail=1
++grep '^rootfs' out || { fail=1; cat out; }
++
++# Ensure that the rootfs is omitted in all_fs mode when it is explicitly
++# black-listed.
++df -a -x rootfs >out || fail=1
++grep '^rootfs' out && { fail=1; cat out; }
++
++Exit $fail
+diff -urNp coreutils-8.12-orig/tests/Makefile.am coreutils-8.12/tests/Makefile.am
+--- coreutils-8.12-orig/tests/Makefile.am	2011-04-25 11:45:27.000000000 +0200
++++ coreutils-8.12/tests/Makefile.am	2012-12-12 13:28:29.592155734 +0100
+@@ -352,6 +352,8 @@ TESTS =						\
+   cp/symlink-slash				\
+   cp/thru-dangling				\
+   df/unreadable					\
++  df/skip-duplicates			        \
++  df/skip-rootfs		 	        \
+   dd/direct					\
+   dd/misc					\
+   dd/nocache					\
diff --git a/coreutils-df-direct.patch b/coreutils-df-direct.patch
index 025323d..d242ffc 100644
--- a/coreutils-df-direct.patch
+++ b/coreutils-df-direct.patch
@@ -67,7 +67,7 @@ diff -urNp coreutils-8.11-orig/src/df.c coreutils-8.11/src/df.c
 +      char *resolved = canonicalize_file_name (name);
 +      if (resolved)
 +	{
-+	  get_dev (NULL, resolved, NULL, NULL, false, false, NULL);
++	  get_dev (NULL, resolved, NULL, NULL, false, false, NULL, false);
 +	  free (resolved);
 +	  return;
 +	}
diff --git a/coreutils.spec b/coreutils.spec
index 8cbb6c7..703abd5 100644
--- a/coreutils.spec
+++ b/coreutils.spec
@@ -1,7 +1,7 @@
 Summary: A set of basic GNU tools commonly used in shell scripts
 Name:    coreutils
 Version: 8.12
-Release: 8%{?dist}
+Release: 9%{?dist}
 License: GPLv3+
 Group:   System Environment/Base
 Url:     http://www.gnu.org/software/coreutils/
@@ -20,6 +20,7 @@ Source203:  coreutils-runuser-l.pamd
 # From upstream
 Patch1: coreutils-8.12-chown.patch
 Patch2: coreutils-8.17-cp-freememoryread.patch
+Patch3: coreutils-8.17-df-duplicates.patch
 
 # Our patches
 #general patch to workaround koji build system issues
@@ -123,6 +124,7 @@ Libraries for coreutils package.
 # From upstream
 %patch1 -p1 -b .chown
 %patch2 -p1 -b .cpfmr
+%patch3 -p1 -b .duplic
 
 # Our patches
 %patch100 -p1 -b .configure
@@ -343,6 +345,10 @@ fi
 %{_libexecdir}/coreutils
 
 %changelog
+* Wed Dec 12 2012 Ondrej Vasik <ovasik at redhat.com> - 8.12-9
+- fix showing duplicates in df (#709351, O.Oprala, B.Voelker)
+- df: work around long-named /dev/disk/by-uuid/... symlinks
+
 * Mon Nov 05 2012 Ondrej Vasik <ovasik at redhat.com> - 8.12-8
 - fix support for ecryptfs mount of "Private" in su (#722323)
 - cp: avoid data-corrupting free-memory-read (upstream fix)


More information about the scm-commits mailing list