OSDN Git Service

Add stat -tL and -c %m%t%T.
authorRob Landley <rob@landley.net>
Mon, 16 May 2016 17:24:42 +0000 (12:24 -0500)
committerRob Landley <rob@landley.net>
Mon, 16 May 2016 17:24:42 +0000 (12:24 -0500)
Suggested by Sameer Pradhan, or possibly Bilal Qureshi.

toys/other/stat.c

index fb5922c..47c10b4 100644 (file)
@@ -2,26 +2,30 @@
  * Copyright 2012 <warior.linux@gmail.com>
  * Copyright 2013 <anand.sinha85@gmail.com>
 
-USE_STAT(NEWTOY(stat, "<1c:f", TOYFLAG_BIN)) 
+USE_STAT(NEWTOY(stat, "<1c:fLt", TOYFLAG_BIN)) 
 
 config STAT
   bool stat
   default y
   help
-    usage: stat [-f] [-c FORMAT] FILE...
+    usage: stat [-tfL] [-c FORMAT] FILE...
 
     Display status of files or filesystems.
 
-    -f display filesystem status instead of file status
-    -c Output specified FORMAT string instead of default
+    -c Output specified FORMAT string instead of default
+    -f display filesystem status instead of file status
+    -L Follow symlinks
+    -t terse (-c "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o")
+             (with -f = -c "%n %i %l %t %s %S %b %f %a %c %d")
 
     The valid format escape sequences for files:
     %a  Access bits (octal) |%A  Access bits (flags)|%b  Blocks allocated
     %B  Bytes per block     |%d  Device ID (dec)    |%D  Device ID (hex)
     %f  All mode bits (hex) |%F  File type          |%g  Group ID
     %G  Group name          |%h  Hard links         |%i  Inode
-    %n  Filename            |%N  Long filename      |%o  I/O block size
-    %s  Size (bytes)        |%u  User ID            |%U  User name
+    %m  Mount point         |%n  Filename           |%N  Long filename
+    %o  I/O block size      |%s  Size (bytes)       |%t  Devtype major (hex)
+    %T  Devtype minor (hex) |%u  User ID            |%U  User name
     %x  Access time         |%X  Access unix time   |%y  File write time
     %Y  File write unix time|%z  Dir change time    |%Z  Dir change unix time
 
@@ -29,7 +33,7 @@ config STAT
     %a  Available blocks    |%b  Total blocks       |%c  Total inodes
     %d  Free inodes         |%f  Free blocks        |%i  File system ID
     %l  Max filename length |%n  File name          |%s  Fragment size
-    %S  Best transfer size  |%t  Filesystem type    |%T  Filesystem type name
+    %S  Best transfer size  |%t  FS type (hex)      |%T  FS type (driver name)
 */
 
 #define FOR_stat
@@ -44,6 +48,7 @@ GLOBALS(
   } stat;
   struct passwd *user_name;
   struct group *group_name;
+  char *file;
 )
 
 
@@ -92,13 +97,25 @@ static void print_stat(char type)
   else if (type == 'G') xprintf("%8s", TT.group_name->gr_name);
   else if (type == 'h') out('u', stat->st_nlink);
   else if (type == 'i') out('u', stat->st_ino);
-  else if (type == 'N') {
-    xprintf("`%s'", *toys.optargs);
+  else if (type == 'm') {
+    struct mtab_list *mt = xgetmountlist(0);
+    dev_t dev = stat->st_rdev ? stat->st_rdev : stat->st_dev;
+
+    // This mount point could exist multiple times, so show oldest.
+    for (dlist_terminate(mt); mt; mt = mt->next) if (mt->stat.st_dev == dev) {
+      printf("%s", mt->dir);
+      break;
+    }
+    llist_traverse(mt, free);
+  } else if (type == 'N') {
+    xprintf("`%s'", TT.file);
     if (S_ISLNK(stat->st_mode))
-      if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf)))
+      if (0<readlink(TT.file, toybuf, sizeof(toybuf)))
         xprintf(" -> `%s'", toybuf);
   } else if (type == 'o') out('u', stat->st_blksize);
   else if (type == 's') out('u', stat->st_size);
+  else if (type == 't') out('x', major(stat->st_rdev));
+  else if (type == 'T') out('x', minor(stat->st_rdev));
   else if (type == 'u') out('u', stat->st_uid);
   else if (type == 'U') xprintf("%8s", TT.user_name->pw_name);
   else if (type == 'x') date_stat_format((void *)&stat->st_atime);
@@ -146,8 +163,13 @@ static void print_statfs(char type) {
 
 void stat_main(void)
 {
-  int flagf = toys.optflags & FLAG_f;
-  char *format = flagf
+  int flagf = toys.optflags & FLAG_f, i;
+  char *format, *f;
+
+  if (toys.optflags&FLAG_t) {
+    format = flagf ? "%n %i %l %t %s %S %b %f %a %c %d" :
+                     "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
+  } else format = flagf
     ? "  File: \"%n\"\n    ID: %i Namelen: %l    Type: %t\n"
       "Block Size: %s    Fundamental block size: %S\n"
       "Blocks: Total: %b\tFree: %f\tAvailable: %a\n"
@@ -159,25 +181,26 @@ void stat_main(void)
 
   if (toys.optflags & FLAG_c) format = TT.fmt;
 
-  for (; *toys.optargs; toys.optargs++) {
-    char *f;
+  for (i = 0; toys.optargs[i]; i++) {
+    int L = toys.optflags & FLAG_L;
 
-    if (flagf && !statfs(*toys.optargs, (void *)&TT.stat));
-    else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) {
+    TT.file = toys.optargs[i];
+    if (flagf && !statfs(TT.file, (void *)&TT.stat));
+    else if (!flagf && !(L ? stat : lstat)(TT.file, (void *)&TT.stat)) {
       struct stat *stat = (struct stat*)&TT.stat;
 
       // check user and group name
       TT.user_name = getpwuid(stat->st_uid);
       TT.group_name = getgrgid(stat->st_gid);
     } else {
-      perror_msg("'%s'", *toys.optargs);
+      perror_msg("'%s'", TT.file);
       continue;
     }
 
     for (f = format; *f; f++) {
       if (*f != '%') putchar(*f);
       else {
-        if (*++f == 'n') xprintf("%s", *toys.optargs);
+        if (*++f == 'n') xprintf("%s", TT.file);
         else if (flagf) print_statfs(*f);
         else print_stat(*f);
       }