From 33efb15fe7b48f73e95d4c2bc9efc400fed25fa5 Mon Sep 17 00:00:00 2001 From: Aaron Burgemeister Date: Fri, 2 Jul 2010 14:07:24 -0600 Subject: [PATCH] stat enhanced to show mountpoint of file/directory Change to implement a new format option %m which shows the mountpoint of the files/directories pointed-to by stat. Currently in order to get the mountpoint of any file/directory an individual can either use df (unintuitive) or they can write code to do this on their own. The code to do this already exists in df and was taken from there to work within the stat command. The default output of stat is to print several data about the file all at once and this was also changed to add a new line showing the mountpoint. Signed-off-by: Aaron Burgemeister --- src/stat.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 89 insertions(+), 0 deletions(-) diff --git a/src/stat.c b/src/stat.c index f1b5ef1..611221e 100644 --- a/src/stat.c +++ b/src/stat.c @@ -68,6 +68,8 @@ #include "quotearg.h" #include "stat-time.h" #include "strftime.h" +#include "xgetcwd.h" +#include "save-cwd.h" #if USE_STATVFS # define STRUCT_STATVFS struct statvfs @@ -179,6 +181,87 @@ static bool interpret_backslash_escapes; "" for --printf=FMT, "\n" for --format=FMT (-c). */ static char const *trailing_delim = ""; +/* Return the root mountpoint of the file system on which FILE exists, in + * malloced storage. FILE_STAT should be the result of stating FILE. + * Give a diagnostic and return NULL if unable to determine the mount point. + * Exit if unable to restore current working directory. */ +static char * +find_mount_point (const char *file, const struct stat *file_stat) +{ + struct saved_cwd cwd; + struct stat last_stat; + char *mp = NULL; /* The malloced mount point. */ + if (save_cwd (&cwd) != 0) + { + error (0, errno, _("cannot get current directory")); + return NULL; + } + if (S_ISDIR (file_stat->st_mode)) + /* FILE is a directory, so just chdir there directly. */ + { + last_stat = *file_stat; + if (chdir (file) < 0) + { + error (0, errno, _("cannot change to directory %s"), quote (file)); + return NULL; + } + } + else + /* FILE is some other kind of file; use its directory. */ + { + char *xdir = dir_name (file); + char *dir; + ASSIGN_STRDUPA (dir, xdir); + free (xdir); + if (chdir (dir) < 0) + { + error (0, errno, _("cannot change to directory %s"), quote (dir)); + return NULL; + } + if (stat (".", &last_stat) < 0) + { + error (0, errno, _("cannot stat current directory (now %s)"), + quote (dir)); + goto done; + } + } + /* Now walk up FILE's parents until we find another file system or /, + * chdiring as we go. LAST_STAT holds stat information for the last place + * we visited. */ + while (true) + { + struct stat st; + if (stat ("..", &st) < 0) + { + error (0, errno, _("cannot stat %s"), quote ("..")); + goto done; + } + if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino) + /* cwd is the mount point. */ + break; + if (chdir ("..") < 0) + { + error (0, errno, _("cannot change to directory %s"), quote ("..")); + goto done; + } + last_stat = st; + } + /* Finally reached a mount point, see what it's called. */ + mp = xgetcwd (); +done: + /* Restore the original cwd. */ + { + int save_errno = errno; + if (restore_cwd (&cwd) != 0) + error (EXIT_FAILURE, errno, + _("failed to return to initial working directory")); + free_cwd (&cwd); + errno = save_errno; + } + return mp; +} + + /* Return the type of the specified file system. Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris). Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0). @@ -671,6 +754,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': + out_string (pformat, prefix_len, find_mount_point (filename, statbuf)); + break; case 'T': out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev)); break; @@ -942,6 +1028,7 @@ do_stat (char const *filename, bool terse, char const *format) { format = " File: %N\n" + " Mountpoint: %m\n" " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" "Device: %Dh/%dd\tInode: %-10i Links: %-5h" " Device type: %t,%T\n" @@ -952,6 +1039,7 @@ do_stat (char const *filename, bool terse, char const *format) { format = " File: %N\n" + " Mountpoint: %m\n" " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" "Device: %Dh/%dd\tInode: %-10i Links: %h\n" "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" @@ -1009,6 +1097,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\ -- 1.7.1