summaryrefslogtreecommitdiff
path: root/src/stat.c
diff options
context:
space:
mode:
authorAaron Burgemeister <dajoker@gmail.com>2010-07-15 19:54:49 -0600
committerPádraig Brady <P@draigBrady.com>2010-08-27 22:16:10 +0100
commitddf6fb8686b1ed6a26d5f1c76a642d0fb5fe7ba7 (patch)
tree27c8712c7d87a57181506c24f2b2ebb58769646c /src/stat.c
parent872f6bb2ba11c61271bf34057a2e950abb3e952e (diff)
downloadcoreutils-ddf6fb8686b1ed6a26d5f1c76a642d0fb5fe7ba7.tar.xz
stat: add %m to output the mount point for a file
* src/find-mount-point.c: A new file refactoring find_mount_point() out from df.c * src/find-mount-point.h: Likewise. * src/df.c: Use the new find-mount-point module. * src/stat.c (print_stat): Handle the new %m format. (find_bind_mount): A new function to return the bind mount for a file if any. (out_mount_mount): Print the bind mount for a file, or else the standard mount point given by the find-mount-point module. (usage): Document the %m format directive. * src/Makefile.am: Reference the refactored find-mount-point.c * po/POTFILES.in: Add find_mount_point.c to the translation list * doc/coreutils.texi (stat invocation): Document %m, and how it may differ from the mount point that df outputs. * test/misc/stat-mount: A new test to correlate mount points output from df and stat. * tests/Makefile.am: Reference the new test. * NEWS: Mention the new feature * THANKS: Add the author Signed-off-by: Pádraig Brady <P@draigBrady.com>
Diffstat (limited to 'src/stat.c')
-rw-r--r--src/stat.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/stat.c b/src/stat.c
index 18a746f97..f98597885 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -64,10 +64,12 @@
#include "filemode.h"
#include "fs.h"
#include "getopt.h"
+#include "mountlist.h"
#include "quote.h"
#include "quotearg.h"
#include "stat-time.h"
#include "strftime.h"
+#include "find-mount-point.h"
#if USE_STATVFS
# define STRUCT_STATVFS struct statvfs
@@ -604,6 +606,94 @@ print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
return fail;
}
+/* Return any bind mounted source for a path.
+ The caller should not free the returned buffer.
+ Return NULL if no bind mount found. */
+static char const * ATTRIBUTE_WARN_UNUSED_RESULT
+find_bind_mount (char const * name)
+{
+ char const * bind_mount = NULL;
+
+ static struct mount_entry *mount_list;
+ static bool tried_mount_list = false;
+ if (!tried_mount_list) /* attempt/warn once per process. */
+ {
+ if (!(mount_list = read_file_system_list (false)))
+ error (0, errno, "%s", _("cannot read table of mounted file systems"));
+ tried_mount_list = true;
+ }
+
+ struct mount_entry *me;
+ for (me = mount_list; me; me = me->me_next)
+ {
+ if (me->me_dummy && me->me_devname[0] == '/'
+ && STREQ (me->me_mountdir, name))
+ {
+ struct stat name_stats;
+ struct stat dev_stats;
+
+ if (stat (name, &name_stats) == 0
+ && stat (me->me_devname, &dev_stats) == 0
+ && SAME_INODE (name_stats, dev_stats))
+ {
+ bind_mount = me->me_devname;
+ break;
+ }
+ }
+ }
+
+ return bind_mount;
+}
+
+/* Print mount point. Return zero upon success, nonzero upon failure. */
+static bool ATTRIBUTE_WARN_UNUSED_RESULT
+out_mount_point (char const *filename, char *pformat, size_t prefix_len,
+ const struct stat *statp)
+{
+
+ char const *np = "?", *bp = NULL;
+ char *mp = NULL;
+ bool fail = true;
+
+ /* Look for bind mounts first. Note we output the immediate alias,
+ rather than further resolving to a base device mount point. */
+ if (follow_links || !S_ISLNK (statp->st_mode))
+ {
+ char *resolved = canonicalize_file_name (filename);
+ if (!resolved)
+ {
+ error (0, errno, _("failed to canonicalize %s"), quote (filename));
+ goto print_mount_point;
+ }
+ bp = find_bind_mount (resolved);
+ free (resolved);
+ if (bp)
+ {
+ fail = false;
+ goto print_mount_point;
+ }
+ }
+
+ /* If there is no direct bind mount, then navigate
+ back up the tree looking for a device change.
+ Note we don't detect if any of the directory components
+ are bind mounted to the same device, but that's OK
+ since we've not directly queried them. */
+ if ((mp = find_mount_point (filename, statp)))
+ {
+ /* This dir might be bind mounted to another device,
+ so we resolve the bound source in that case also. */
+ bp = find_bind_mount (mp);
+ fail = false;
+ }
+
+print_mount_point:
+
+ out_string (pformat, prefix_len, bp ? bp : mp ? mp : np);
+ free (mp);
+ return fail;
+}
+
/* Print stat info. Return zero upon success, nonzero upon failure. */
static bool
print_stat (char *pformat, size_t prefix_len, char m,
@@ -680,6 +770,9 @@ print_stat (char *pformat, size_t prefix_len, char m,
case 't':
out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
break;
+ case 'm':
+ fail |= out_mount_point (filename, pformat, prefix_len, statbuf);
+ break;
case 'T':
out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
break;
@@ -1026,6 +1119,7 @@ The valid format sequences for files (without --file-system):\n\
fputs (_("\
%h Number of hard links\n\
%i Inode number\n\
+ %m Mount point\n\
%n File name\n\
%N Quoted file name with dereference if symbolic link\n\
%o I/O block size\n\