From: Pádraig Brady
Date: Sun, 20 Jun 2021 14:16:49 +0000 (+0100) Subject: stat: support more device number representations X-Git-Tag: v9.0~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a8278229e0ead89231b3d44d747fe3c10767596;p=thirdparty%2Fcoreutils.git stat: support more device number representations 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 --- diff --git a/NEWS b/NEWS index c216d22dab..a2d28cfc86 100644 --- 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 diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 3e3aedb0f9..ea040458e0 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -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. diff --git a/src/stat.c b/src/stat.c index 56e4867b92..0f3039b583 100644 --- a/src/stat.c +++ b/src/stat.c @@ -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); diff --git a/tests/misc/stat-fmt.sh b/tests/misc/stat-fmt.sh index 38d05bd4a4..09a4e1b937 100755 --- a/tests/misc/stat-fmt.sh +++ b/tests/misc/stat-fmt.sh @@ -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