Hi, this patch adds the --dereference option to df, so if a symlink is specified
as an argument to df (possibly /dev/disk/by-uuid/*), df outputs info about the
filesystem the symlinked file is on instead. Now, I realize the option's name is
a bit misleading, since the arguments are stat-ed anyway, but IMHO that's 
exactly
what it looks like from a user's perspective.

Thanks,
Ondrej
From 94125f4646c61f75ec2c872cd945d0a31a4cc80a Mon Sep 17 00:00:00 2001
From: Ondrej Oprala <[email protected]>
Date: Wed, 15 May 2013 14:34:27 +0200
Subject: [PATCH] df: add the --dereference option

With --dereference specified, df should print info about the
filesystem the pointed-to file is on if a symlink is passed
as an argument to df.

* NEWS: Mention the new feature.
* doc/coreutils.texi: Likewise.
* src/df.c: Add new static global variable dereference.
(get_point): Use me_devname while looking for best match instead
of me_mountdir if --dereference was specified.
---
 NEWS               |  4 ++++
 doc/coreutils.texi |  8 ++++++++
 src/df.c           | 23 +++++++++++++++++++----
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/NEWS b/NEWS
index eec93df..6d7def3 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,10 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** New features
 
+	df accepts a new option: --dereference (-L). If a symlink is passed as an
+	argument, df prints information about the filesystem the pointed-to file
+	is on instead.
+
   id -Z reports the SMACK security context where available.
 
   join accepts a new option: --zero-terminated (-z). As with the sort,uniq
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index d607eaf..52db41b 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11097,6 +11097,14 @@ This option is equivalent to @option{--block-size=1K}.
 Limit the listing to local file systems.  By default, remote file systems
 are also listed.
 
+@item -L
+@itemx --dereference
+@opindex -L
+@opindex --dereference
+@cindex symlink dereferencing
+Print the actual mount point if a symlink is passed as an argument
+to @command{df}.
+
 @item --no-sync
 @opindex --no-sync
 @cindex file system space, retrieving old data more quickly
diff --git a/src/df.c b/src/df.c
index 0515131..21b07e9 100644
--- a/src/df.c
+++ b/src/df.c
@@ -66,6 +66,9 @@ static bool show_listed_fs;
 /* Human-readable options for output.  */
 static int human_output_opts;
 
+/* Show the actual mount point if a symlink is passed as an argument.  */
+static bool dereference;
+
 /* The units to use when printing sizes.  */
 static uintmax_t output_block_size;
 
@@ -249,6 +252,7 @@ static struct option const long_options[] =
   {"human-readable", no_argument, NULL, 'h'},
   {"si", no_argument, NULL, 'H'},
   {"local", no_argument, NULL, 'l'},
+  {"dereference", no_argument, NULL, 'L'},
   {"megabytes", no_argument, NULL, MEGABYTES_OPTION}, /* obsolescent,  */
   {"output", optional_argument, NULL, OUTPUT_OPTION},
   {"portability", no_argument, NULL, 'P'},
@@ -1071,11 +1075,17 @@ get_point (const char *point, const struct stat *statp)
       if (!STREQ (me->me_type, "lofs")
           && (!best_match || best_match->me_dummy || !me->me_dummy))
         {
-          size_t len = strlen (me->me_mountdir);
+	  size_t len;
+	  if (dereference)
+	    len = strlen (me->me_devname);
+	  else
+	    len = strlen (me->me_mountdir);
+
           if (best_match_len <= len && len <= resolved_len
               && (len == 1 /* root file system */
                   || ((len == resolved_len || resolved[len] == '/')
-                      && STREQ_LEN (me->me_mountdir, resolved, len))))
+                      && ((dereference && STREQ_LEN (me->me_devname, resolved, len))
+                      || STREQ_LEN (me->me_mountdir, resolved, len)))))
             {
               best_match = me;
               best_match_len = len;
@@ -1085,7 +1095,7 @@ get_point (const char *point, const struct stat *statp)
   free (resolved);
   if (best_match
       && (stat (best_match->me_mountdir, &disk_stats) != 0
-          || disk_stats.st_dev != statp->st_dev))
+          || (!dereference && disk_stats.st_dev != statp->st_dev)))
     best_match = NULL;
 
   if (! best_match)
@@ -1230,6 +1240,7 @@ or all file systems by default.\n\
   -l, --local           limit listing to local file systems\n\
       --no-sync         do not invoke sync before getting usage info (default)\
 \n\
+  -L  --dereference     show the actual mount point if a symlink is given\n\
 "), stdout);
       fputs (_("\
       --output[=FIELD_LIST]  use the output format defined by FIELD_LIST,\n\
@@ -1272,6 +1283,7 @@ main (int argc, char **argv)
   fs_exclude_list = NULL;
   show_all_fs = false;
   show_listed_fs = false;
+  dereference = false;
   human_output_opts = -1;
   print_type = false;
   file_systems_processed = false;
@@ -1287,7 +1299,7 @@ main (int argc, char **argv)
   while (true)
     {
       int oi = -1;
-      int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
+      int c = getopt_long (argc, argv, "aB:iF:hHklLmPTt:vx:", long_options,
                            &oi);
       if (c == -1)
         break;
@@ -1328,6 +1340,9 @@ main (int argc, char **argv)
         case 'l':
           show_local_fs = true;
           break;
+	case 'L':
+	  dereference = true;
+	  break;
         case MEGABYTES_OPTION:
           /* Distinguish between the long and the short option.
              As we want to remove the long option soon,
-- 
1.8.1.4

Reply via email to