]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
stat: support more device number representations
authorPádraig Brady <P@draigBrady.com>
Sun, 20 Jun 2021 14:16:49 +0000 (15:16 +0100)
committerPádraig Brady <P@draigBrady.com>
Mon, 21 Jun 2021 11:01:04 +0000 (12:01 +0100)
In preparation for changing the default device number
representation (to decomposed decimal), provide more
formatting options for device numbers.

These new (FreeBSD compat) formatting options are added:

   %Hd  major device number in decimal (st_dev)
   %Ld  minor device number in decimal (st_dev)
   %Hr  major device type in decimal (st_rdev)
   %Lr  minor device type in decimal (st_rdev)
   %r   (composed) device type in decimal (st_rdev)
   %R   (composed) device type in hex (st_rdev)

* doc/coreutils.texi (stat invocation): Document new formats.
* src/stat.c (print_it): Handle the new %H and %L modifiers.
(print_statfs): Adjust to passing the format as two chars
rather than an int.  Using an int was introduced in commit db42ae78,
but using separate chars is cleaner and more extensible.
(print_stat): Likewise.  Handle any modifiers and the new 'r' format.
(usage): Document the new formats.
* tests/misc/stat-fmt.sh: Add a test case for new modifiers.
Addresses https://bugs.gnu.org/48960

NEWS
doc/coreutils.texi
src/stat.c
tests/misc/stat-fmt.sh

diff --git a/NEWS b/NEWS
index c216d22dab9a6a1bc9cde1f6b84842277efa793d..a2d28cfc860f416159c7bbae19bb3a896714d646 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -75,6 +75,10 @@ GNU coreutils NEWS                                    -*- outline -*-
 
   nl --line-increment can now take a negative number to decrement the count.
 
+  stat supports more formats for representing decomposed device numbers.
+  %Hd,%Ld and %Hr,%Lr will output major,minor device numbers and device types
+  respectively.  %d corresponds to st_dev and %r to std_rdev.
+
 ** Improvements
 
   cat --show-ends will now show \r\n as ^M$.  Previously the \r was taken
index 3e3aedb0f988267df04d77849537bdbebd5221ef..ea040458e0b33a8d239e4e16a4d55f90ee7778ec 100644 (file)
@@ -12506,8 +12506,10 @@ The valid @var{format} directives for files with @option{--format} and
 @item %b - Number of blocks allocated (see @samp{%B})
 @item %B - The size in bytes of each block reported by @samp{%b}
 @item %C - The SELinux security context of a file, if available
-@item %d - Device number in decimal
-@item %D - Device number in hex
+@item %d - Device number in decimal (st_dev)
+@item %D - Device number in hex (st_dev)
+@item %Hd - Major device number in decimal
+@item %Ld - Minor device number in decimal
 @item %f - Raw mode in hex
 @item %F - File type
 @item %g - Group ID of owner
@@ -12519,6 +12521,10 @@ The valid @var{format} directives for files with @option{--format} and
 @item %N - Quoted file name with dereference if symbolic link (see below)
 @item %o - Optimal I/O transfer size hint
 @item %s - Total size, in bytes
+@item %r - Device type in decimal (st_rdev)
+@item %R - Device type in hex (st_rdev)
+@item %Hr - Major device type in decimal (see below)
+@item %Lr - Minor device type in decimal (see below)
 @item %t - Major device type in hex (see below)
 @item %T - Minor device type in hex (see below)
 @item %u - User ID of owner
@@ -12543,8 +12549,9 @@ The @samp{%N} format can be set with the environment variable
 the default value is @samp{shell-escape-always}.  Valid quoting styles are:
 @quotingStyles
 
-The @samp{%t} and @samp{%T} formats operate on the st_rdev member of
-the stat(2) structure, and are only defined for character and block
+The @samp{r}, @samp{R}, @samp{%t}, and @samp{%T} formats operate on the st_rdev
+member of the stat(2) structure, i.e., the represented device rather than
+the containing device, and so are only defined for character and block
 special files.  On some systems or file types, st_rdev may be used to
 represent other quantities.
 
index 56e4867b921070e4c4223646f4f8b5d6937e03aa..0f3039b58376c415906aef8cfb8692f401a13730 100644 (file)
@@ -247,7 +247,7 @@ static char const *decimal_point;
 static size_t decimal_point_len;
 
 static bool
-print_stat (char *pformat, size_t prefix_len, unsigned int m,
+print_stat (char *pformat, size_t prefix_len, char mod, char m,
             int fd, char const *filename, void const *data);
 
 /* Return the type of the specified file system.
@@ -852,7 +852,7 @@ out_file_context (char *pformat, size_t prefix_len, char const *filename)
 
 /* Print statfs info.  Return zero upon success, nonzero upon failure.  */
 static bool ATTRIBUTE_WARN_UNUSED_RESULT
-print_statfs (char *pformat, size_t prefix_len, unsigned int m,
+print_statfs (char *pformat, size_t prefix_len, char mod _GL_UNUSED, char m,
               int fd, char const *filename,
               void const *data)
 {
@@ -1119,7 +1119,7 @@ format_code_offset (char const* directive)
    Return zero upon success, nonzero upon failure.  */
 static bool ATTRIBUTE_WARN_UNUSED_RESULT
 print_it (char const *format, int fd, char const *filename,
-          bool (*print_func) (char *, size_t, unsigned int,
+          bool (*print_func) (char *, size_t, char, char,
                               int, char const *, void const *),
           void const *data)
 {
@@ -1144,11 +1144,12 @@ print_it (char const *format, int fd, char const *filename,
         case '%':
           {
             size_t len = format_code_offset (b);
-            char const *fmt_char = b + len;
+            char fmt_char = *(b + len);
+            char mod_char = 0;
             memcpy (dest, b, len);
             b += len;
 
-            switch (*fmt_char)
+            switch (fmt_char)
               {
               case '\0':
                 --b;
@@ -1156,15 +1157,30 @@ print_it (char const *format, int fd, char const *filename,
               case '%':
                 if (1 < len)
                   {
-                    dest[len] = *fmt_char;
+                    dest[len] = fmt_char;
                     dest[len + 1] = '\0';
                     die (EXIT_FAILURE, 0, _("%s: invalid directive"),
                          quote (dest));
                   }
                 putchar ('%');
                 break;
+              case 'H':
+              case 'L':
+                mod_char = fmt_char;
+                fmt_char = *(b + 1);
+                if (print_func == print_stat
+                    && (fmt_char == 'd' || fmt_char == 'r'))
+                  {
+                    b++;
+                  }
+                else
+                  {
+                    fmt_char = mod_char;
+                    mod_char = 0;
+                  }
+                FALLTHROUGH;
               default:
-                fail |= print_func (dest, len, to_uchar (*fmt_char),
+                fail |= print_func (dest, len, mod_char, fmt_char,
                                     fd, filename, data);
                 break;
               }
@@ -1460,7 +1476,7 @@ do_stat (char const *filename, char const *format,
 
 /* Print stat info.  Return zero upon success, nonzero upon failure.  */
 static bool
-print_stat (char *pformat, size_t prefix_len, unsigned int m,
+print_stat (char *pformat, size_t prefix_len, char mod, char m,
             int fd, char const *filename, void const *data)
 {
   struct print_args *parg = (struct print_args *) data;
@@ -1492,7 +1508,12 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m,
         }
       break;
     case 'd':
-      out_uint (pformat, prefix_len, statbuf->st_dev);
+      if (mod == 'H')
+        out_uint (pformat, prefix_len, major (statbuf->st_dev));
+      else if (mod == 'L')
+        out_uint (pformat, prefix_len, minor (statbuf->st_dev));
+      else
+        out_uint (pformat, prefix_len, statbuf->st_dev);
       break;
     case 'D':
       out_uint_x (pformat, prefix_len, statbuf->st_dev);
@@ -1537,6 +1558,17 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m,
     case 's':
       out_int (pformat, prefix_len, statbuf->st_size);
       break;
+    case 'r':
+      if (mod == 'H')
+        out_uint (pformat, prefix_len, major (statbuf->st_rdev));
+      else if (mod == 'L')
+        out_uint (pformat, prefix_len, minor (statbuf->st_rdev));
+      else
+        out_uint (pformat, prefix_len, statbuf->st_rdev);
+      break;
+    case 'R':
+      out_uint_x (pformat, prefix_len, statbuf->st_rdev);
+      break;
     case 't':
       out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
       break;
@@ -1739,8 +1771,10 @@ The valid format sequences for files (without --file-system):\n\
   %C   SELinux security context string\n\
 "), stdout);
       fputs (_("\
-  %d   device number in decimal\n\
-  %D   device number in hex\n\
+  %d   device number in decimal (st_dev)\n\
+  %D   device number in hex (st_dev)\n\
+  %Hd  major device number in decimal\n\
+  %Ld  minor device number in decimal\n\
   %f   raw mode in hex\n\
   %F   file type\n\
   %g   group ID of owner\n\
@@ -1754,6 +1788,10 @@ The valid format sequences for files (without --file-system):\n\
   %N   quoted file name with dereference if symbolic link\n\
   %o   optimal I/O transfer size hint\n\
   %s   total size, in bytes\n\
+  %r   device type in decimal (st_rdev)\n\
+  %R   device type in hex (st_rdev)\n\
+  %Hr  major device type in decimal, for character/block device special files\n\
+  %Lr  minor device type in decimal, for character/block device special files\n\
   %t   major device type in hex, for character/block device special files\n\
   %T   minor device type in hex, for character/block device special files\n\
 "), stdout);
index 38d05bd4a4c1893ad8786e9e40015aef64d2a445..09a4e1b937627e17b6ed517ef71da9619ff1f53e 100755 (executable)
@@ -40,5 +40,8 @@ cat <<\EOF >exp
 EOF
 compare exp out || fail=1
 
+# ensure %H and %L modifiers are handled
+stat -c '%r %R %Hd,%Ld %Hr,%Lr' . > out || fail=1
+grep -F '?' out && fail=1
 
 Exit $fail