Blame SOURCES/coreutils-df-direct.patch

8d0e4d
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
8d0e4d
index a507280..400e135 100644
8d0e4d
--- a/doc/coreutils.texi
8d0e4d
+++ b/doc/coreutils.texi
8d0e4d
@@ -11303,6 +11303,13 @@ some systems (notably SunOS), doing this yields more up to date results,
8d0e4d
 but in general this option makes @command{df} much slower, especially when
8d0e4d
 there are many or very busy file systems.
8d0e4d
 
8d0e4d
+@item --direct
8d0e4d
+@opindex --direct
8d0e4d
+@cindex direct statfs for a file
8d0e4d
+Do not resolve mount point and show statistics directly for a file. It can be
8d0e4d
+especially useful for NFS mount points if there is a boundary between two
8d0e4d
+storage policies behind the mount point.
8d0e4d
+
8d0e4d
 @item --total
8d0e4d
 @opindex --total
8d0e4d
 @cindex grand total of disk size, usage and available space
8d0e4d
diff --git a/src/df.c b/src/df.c
8d0e4d
index 8f760db..a7385fd 100644
8d0e4d
--- a/src/df.c
8d0e4d
+++ b/src/df.c
8d0e4d
@@ -120,6 +120,9 @@ static bool print_type;
8d0e4d
 /* If true, print a grand total at the end.  */
8d0e4d
 static bool print_grand_total;
8d0e4d
 
8d0e4d
+/* If true, show statistics for a file instead of mount point.  */
8d0e4d
+static bool direct_statfs;
8d0e4d
+
8d0e4d
 /* Grand total data.  */
8d0e4d
 static struct fs_usage grand_fsu;
8d0e4d
 
8d0e4d
@@ -247,13 +250,15 @@ enum
8d0e4d
   NO_SYNC_OPTION = CHAR_MAX + 1,
8d0e4d
   SYNC_OPTION,
8d0e4d
   TOTAL_OPTION,
8d0e4d
-  OUTPUT_OPTION
8d0e4d
+  OUTPUT_OPTION,
8d0e4d
+  DIRECT_OPTION
8d0e4d
 };
8d0e4d
 
8d0e4d
 static struct option const long_options[] =
8d0e4d
 {
8d0e4d
   {"all", no_argument, NULL, 'a'},
8d0e4d
   {"block-size", required_argument, NULL, 'B'},
8d0e4d
+  {"direct", no_argument, NULL, DIRECT_OPTION},
8d0e4d
   {"inodes", no_argument, NULL, 'i'},
8d0e4d
   {"human-readable", no_argument, NULL, 'h'},
8d0e4d
   {"si", no_argument, NULL, 'H'},
8d0e4d
@@ -509,7 +514,10 @@ get_header (void)
8d0e4d
   for (col = 0; col < ncolumns; col++)
8d0e4d
     {
8d0e4d
       char *cell = NULL;
8d0e4d
-      char const *header = _(columns[col]->caption);
8d0e4d
+      char const *header = (columns[col]->field == TARGET_FIELD
8d0e4d
+                            && direct_statfs)?
8d0e4d
+                            _("File") :
8d0e4d
+                            _(columns[col]->caption);
8d0e4d
 
8d0e4d
       if (columns[col]->field == SIZE_FIELD
8d0e4d
           && (header_mode == DEFAULT_MODE
8d0e4d
@@ -1397,6 +1405,19 @@ get_point (const char *point, const struct stat *statp)
8d0e4d
 static void
8d0e4d
 get_entry (char const *name, struct stat const *statp)
8d0e4d
 {
8d0e4d
+  if (direct_statfs)
8d0e4d
+    {
8d0e4d
+      char *resolved = canonicalize_file_name (name);
8d0e4d
+      if (resolved)
8d0e4d
+	{
8d0e4d
+         char *mp = find_mount_point (name, statp);
8d0e4d
+	  get_dev (NULL, mp, resolved, NULL, NULL, false, false, NULL, false);
8d0e4d
+         free(mp);
8d0e4d
+	  free (resolved);
8d0e4d
+	  return;
8d0e4d
+	}
8d0e4d
+    }
8d0e4d
+
8d0e4d
   if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
8d0e4d
       && get_disk (name))
8d0e4d
     return;
8d0e4d
@@ -1467,6 +1488,7 @@ or all file systems by default.\n\
8d0e4d
   -B, --block-size=SIZE  scale sizes by SIZE before printing them; e.g.,\n\
8d0e4d
                            '-BM' prints sizes in units of 1,048,576 bytes;\n\
8d0e4d
                            see SIZE format below\n\
8d0e4d
+      --direct          show statistics for a file instead of mount point\n\
8d0e4d
   -h, --human-readable  print sizes in powers of 1024 (e.g., 1023M)\n\
8d0e4d
   -H, --si              print sizes in powers of 1000 (e.g., 1.1G)\n\
8d0e4d
 "), stdout);
8d0e4d
@@ -1557,6 +1579,9 @@ main (int argc, char **argv)
8d0e4d
               xstrtol_fatal (e, oi, c, long_options, optarg);
8d0e4d
           }
8d0e4d
           break;
8d0e4d
+        case DIRECT_OPTION:
8d0e4d
+          direct_statfs = true;
8d0e4d
+          break;
8d0e4d
         case 'i':
8d0e4d
           if (header_mode == OUTPUT_MODE)
8d0e4d
             {
8d0e4d
@@ -1653,6 +1678,13 @@ main (int argc, char **argv)
8d0e4d
         }
8d0e4d
     }
8d0e4d
 
8d0e4d
+  if (direct_statfs && show_local_fs)
8d0e4d
+    {
8d0e4d
+      error (0, 0, _("options --direct and --local (-l) are mutually "
8d0e4d
+		     "exclusive"));
8d0e4d
+      usage (EXIT_FAILURE);
8d0e4d
+    }
8d0e4d
+
8d0e4d
   if (human_output_opts == -1)
8d0e4d
     {
8d0e4d
       if (posix_format)
8d0e4d
diff --git a/tests/df/direct.sh b/tests/df/direct.sh
8d0e4d
new file mode 100755
8d0e4d
index 0000000..8e4cfb8
8d0e4d
--- /dev/null
8d0e4d
+++ b/tests/df/direct.sh
8d0e4d
@@ -0,0 +1,55 @@
8d0e4d
+#!/bin/sh
8d0e4d
+# Ensure "df --direct" works as documented
8d0e4d
+
8d0e4d
+# Copyright (C) 2010 Free Software Foundation, Inc.
8d0e4d
+
8d0e4d
+# This program is free software: you can redistribute it and/or modify
8d0e4d
+# it under the terms of the GNU General Public License as published by
8d0e4d
+# the Free Software Foundation, either version 3 of the License, or
8d0e4d
+# (at your option) any later version.
8d0e4d
+
8d0e4d
+# This program is distributed in the hope that it will be useful,
8d0e4d
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
8d0e4d
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8d0e4d
+# GNU General Public License for more details.
8d0e4d
+
8d0e4d
+# You should have received a copy of the GNU General Public License
8d0e4d
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
8d0e4d
+
8d0e4d
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
8d0e4d
+print_ver_ df
8d0e4d
+
8d0e4d
+df || skip_ "df fails"
8d0e4d
+
8d0e4d
+DIR=`pwd` || framework_failure
8d0e4d
+FILE="$DIR/file"
8d0e4d
+touch "$FILE" || framework_failure
8d0e4d
+echo "$FILE" > file_exp || framework_failure
8d0e4d
+echo "Mounted on" > header_mounted_exp || framework_failure
8d0e4d
+echo "File" > header_file_exp || framework_failure
8d0e4d
+
8d0e4d
+fail=0
8d0e4d
+
8d0e4d
+df --portability "$FILE" > df_out || fail=1
8d0e4d
+df --portability --direct "$FILE" > df_direct_out || fail=1
8d0e4d
+df --portability --direct --local "$FILE" > /dev/null 2>&1 && fail=1
8d0e4d
+
8d0e4d
+# check df header
8d0e4d
+$AWK '{ if (NR==1) print $6 " " $7; }' df_out > header_mounted_out \
8d0e4d
+  || framework_failure
8d0e4d
+$AWK '{ if (NR==1) print $6; }' df_direct_out > header_file_out \
8d0e4d
+  || framework_failure
8d0e4d
+compare header_mounted_out header_mounted_exp || fail=1
8d0e4d
+compare header_file_out header_file_exp || fail=1
8d0e4d
+
8d0e4d
+# check df output (without --direct)
8d0e4d
+$AWK '{ if (NR==2) print $6; }' df_out > file_out \
8d0e4d
+  || framework_failure
8d0e4d
+compare file_out file_exp && fail=1
8d0e4d
+
8d0e4d
+# check df output (with --direct)
8d0e4d
+$AWK '{ if (NR==2) print $6; }' df_direct_out > file_out \
8d0e4d
+  || framework_failure
8d0e4d
+compare file_out file_exp || fail=1
8d0e4d
+
8d0e4d
+Exit $fail