diff options
author | Aaron Burgemeister <dajoker@gmail.com> | 2010-07-15 19:54:49 -0600 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2010-08-27 22:16:10 +0100 |
commit | ddf6fb8686b1ed6a26d5f1c76a642d0fb5fe7ba7 (patch) | |
tree | 27c8712c7d87a57181506c24f2b2ebb58769646c /src/stat.c | |
parent | 872f6bb2ba11c61271bf34057a2e950abb3e952e (diff) | |
download | coreutils-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.c | 94 |
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\ |