bug#70477: tail command does not hang on /dev/random

2024-04-19 Thread Paul Eggert

On 2024-04-19 11:40, Ionut Nicula wrote:

The following command hangs indefinitely, as expected:

 tail -c 4096 /dev/random

The following command immediately returns 4097 bytes, unexpectedly:

 tail -c 4097 /dev/random


Thanks for the bug report. Although the two commands should behave 
similarly, neither should loop: they should both output the requested 
number of random bytes. Similarly for /dev/zero. I installed the 
attached patch to do that.From fb543b6b82c1f3a20ff88f44cc3ed367bfe811b6 Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Fri, 19 Apr 2024 21:44:32 -0700
Subject: [PATCH] tail: avoid infloop with -c on /dev/zero

Problem reported by Ionut Nicula in:
https://bugs.gnu.org/70477
* src/tail.c (tail_bytes): Do not loop forever on commands
like 'tail -c 4096 /dev/zero'.
* tests/tail/tail-c.sh: Test this fix.
---
 NEWS |  3 +++
 src/tail.c   | 24 +++-
 tests/tail/tail-c.sh | 10 ++
 3 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/NEWS b/NEWS
index 43ce84d7e..389f72516 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ GNU coreutils NEWS-*- outline -*-
   have exited with a "Function not implemented" error.
   [bug introduced in coreutils-8.28]
 
+  'tail -c 4096 /dev/zero' no longer loops forever.
+  [This bug was present in "the beginning".]
+
 ** Changes in behavior
 
   ls's -f option now simply acts like -aU, instead of also ignoring
diff --git a/src/tail.c b/src/tail.c
index 52c081031..a3b46ca2d 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -760,7 +760,8 @@ free_lbuffers:
   return ok;
 }
 
-/* Print the last N_BYTES characters from the end of pipe FD.
+/* Print the last N_BYTES characters from the end of FD.
+   Work even if the input is a pipe.
This is a stripped down version of pipe_lines.
Return true if successful.  */
 
@@ -1875,15 +1876,28 @@ tail_bytes (char const *pretty_filename, int fd, uintmax_t n_bytes,
 {
   off_t end_pos = -1;
   off_t current_pos = -1;
+  bool copy_from_current_pos = false;
 
   if (! presume_input_pipe && n_bytes <= OFF_T_MAX)
 {
   if (usable_st_size ())
-end_pos = stats.st_size;
-  else if ((current_pos = lseek (fd, -n_bytes, SEEK_END)) != -1)
-end_pos = current_pos + n_bytes;
+{
+  /* Use st_size only if it's so large that this is
+ probably not a /proc or similar file, where st_size
+ is notional.  */
+  end_pos = stats.st_size;
+  off_t smallish_size = STP_BLKSIZE ();
+  copy_from_current_pos = smallish_size < end_pos;
+}
+  else
+{
+  current_pos = lseek (fd, -n_bytes, SEEK_END);
+  copy_from_current_pos = current_pos != -1;
+  if (copy_from_current_pos)
+end_pos = current_pos + n_bytes;
+}
 }
-  if (end_pos <= (off_t) STP_BLKSIZE ())
+  if (! copy_from_current_pos)
 return pipe_bytes (pretty_filename, fd, n_bytes, read_pos);
   if (current_pos == -1)
 current_pos = xlseek (fd, 0, SEEK_CUR, pretty_filename);
diff --git a/tests/tail/tail-c.sh b/tests/tail/tail-c.sh
index f518e5b21..a9f2bc2d1 100755
--- a/tests/tail/tail-c.sh
+++ b/tests/tail/tail-c.sh
@@ -35,4 +35,14 @@ printf '123456' | tail -c3 > out || fail=1
 printf '456' > exp || framework_failure_
 compare exp out || fail=1
 
+# Any part of /dev/zero should be valid for tail -c.
+head -c 4096 /dev/zero >exp || fail=1
+tail -c 4096 /dev/zero >out || fail=1
+compare exp out || fail=1
+
+# Any part of /dev/urandom, if it exists, should be valid for tail -c.
+if test -r /dev/urandom; then
+  timeout --verbose 1 tail -c 4096 /dev/urandom >/dev/null || fail=1
+fi
+
 Exit $fail
-- 
2.40.1



bug#70477: tail command does not hang on /dev/random

2024-04-19 Thread Ionut Nicula
The following command hangs indefinitely, as expected:

tail -c 4096 /dev/random

The following command immediately returns 4097 bytes, unexpectedly:

tail -c 4097 /dev/random

Details:
- Source code obtained from: git://git.sv.gnu.org/coreutils
- Commit id: 9ab1f9db94479eca4dd2c29b4e21550ff2bcd5bb
- System:

$ uname -a
Linux zinc 6.1.0-20-amd64 #1 SMP PREEMPT_DYNAMIC Debian
6.1.85-1 (2024-04-11) x86_64 GNU/Linux





bug#70411: [bug] install(1) fails to read /dev/stdin on Darwin

2024-04-19 Thread Sergei Trofimovich
On Fri, 19 Apr 2024 00:33:52 -0700
Paul Eggert  wrote:

> On 2024-04-18 14:52, Sergei Trofimovich wrote:
> > $ clang simple.c -o simple && echo 42 | ./simple
> > 1: ino=3009428657538693161
> > 2: ino=3009428657538693161
> > 3: ino=1568241705
> > 
> > Note how stat() and fstat() don't agree on inode.
> > 
> > Apparently it's documented in
> > https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fstat.2.html
> > as
> > 
> >BUGS
> >   Applying fstat to a socket (and thus to a pipe) returns a zero'd 
> > buffer,
> >   except for the blocksize field, and a unique device and inode number. 
> >  
> 
> The BUGS note simply means that a pipe has a unique inode number, which 
> is what we want. So that's not indicating any problem.
> 
> 
> Oh, I see the problem now.  For a socket or pipe, macOS fstat returns 
> the full 64-bit inode number, whereas macOS stat returns only the low 
> order 32 bits.  In your example, 3009428657538693161 % (2**32) == 
> 1568241705.
> 
> This is a kernel bug in macOS. Can you report it or otherwise arrange to 
> have the kernel bug fixed? I expect that you have better connections 
> with Apple than I do. A proposed patch (relative to xnu-10063.101.15) is 
> attached; I have not tested it as I don't use macOS. Thanks.

I reported it via https://www.apple.com/feedback/macos.html

> Also, I am documenting this macOS bug in Gnulib by installing the second 
> attached patch to Gnulib, and am cc'ing this email to bug-gnulib.

Thank you, Paul!

-- 

  Sergei





bug#70411: [bug] install(1) fails to read /dev/stdin on Darwin

2024-04-19 Thread Paul Eggert

On 2024-04-18 14:52, Sergei Trofimovich wrote:

$ clang simple.c -o simple && echo 42 | ./simple
1: ino=3009428657538693161
2: ino=3009428657538693161
3: ino=1568241705

Note how stat() and fstat() don't agree on inode.

Apparently it's documented in
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fstat.2.html
as

   BUGS
  Applying fstat to a socket (and thus to a pipe) returns a zero'd buffer,
  except for the blocksize field, and a unique device and inode number.


The BUGS note simply means that a pipe has a unique inode number, which 
is what we want. So that's not indicating any problem.



Oh, I see the problem now.  For a socket or pipe, macOS fstat returns 
the full 64-bit inode number, whereas macOS stat returns only the low 
order 32 bits.  In your example, 3009428657538693161 % (2**32) == 
1568241705.


This is a kernel bug in macOS. Can you report it or otherwise arrange to 
have the kernel bug fixed? I expect that you have better connections 
with Apple than I do. A proposed patch (relative to xnu-10063.101.15) is 
attached; I have not tested it as I don't use macOS. Thanks.


Also, I am documenting this macOS bug in Gnulib by installing the second 
attached patch to Gnulib, and am cc'ing this email to bug-gnulib.From 29345117a4cf85aceb88e3901758b19a4867062e Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Fri, 19 Apr 2024 00:12:50 -0700
Subject: [PATCH] Fix bug with stat truncating pipe/socket st_ino

Problem reported by Sergei Trofimovich in:
https://bugs.gnu.org/70411
https://github.com/NixOS/nixpkgs/pull/300797
* bsd/miscfs/devfs/devfs_fdesc_support.c (fdesc_attr):
Do not truncate inode numbers to 32 bits.
---
 bsd/miscfs/devfs/devfs_fdesc_support.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bsd/miscfs/devfs/devfs_fdesc_support.c b/bsd/miscfs/devfs/devfs_fdesc_support.c
index a17c6992..b4a55103 100644
--- a/bsd/miscfs/devfs/devfs_fdesc_support.c
+++ b/bsd/miscfs/devfs/devfs_fdesc_support.c
@@ -437,10 +437,10 @@ fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context)
 	case DTYPE_PIPE:
 #if SOCKETS
 		if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
-			error = soo_stat((struct socket *)fp_get_data(fp), (void *), 0);
+			error = soo_stat((struct socket *)fp_get_data(fp), (void *), 1);
 		} else
 #endif /* SOCKETS */
-		error = pipe_stat((struct pipe *)fp_get_data(fp), (void *), 0);
+		error = pipe_stat((struct pipe *)fp_get_data(fp), (void *), 1);
 
 		if (error == 0) {
 			if (FILEGLOB_DTYPE(fp->fp_glob) == DTYPE_SOCKET) {
-- 
2.44.0

From c2174a623d33096b52f4d7fd2963f76acb3e301f Mon Sep 17 00:00:00 2001
From: Paul Eggert 
Date: Fri, 19 Apr 2024 00:29:32 -0700
Subject: [PATCH] fstatat, stat: document macOS st_ino pipe bug

* doc/posix-functions/fstatat.texi (fstatat):
* doc/posix-functions/stat.texi (stat):
Document macOS bug (see ).
---
 ChangeLog| 7 +++
 doc/posix-functions/fstatat.texi | 5 +
 doc/posix-functions/stat.texi| 5 +
 3 files changed, 17 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 7ce75a98a9..1667f90c55 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2024-04-19  Paul Eggert  
+
+	fstatat, stat: document macOS st_ino pipe bug
+	* doc/posix-functions/fstatat.texi (fstatat):
+	* doc/posix-functions/stat.texi (stat):
+	Document macOS bug (see ).
+
 2024-04-18  Bruno Haible  
 
 	totalordermagl: Add tests.
diff --git a/doc/posix-functions/fstatat.texi b/doc/posix-functions/fstatat.texi
index e959a5cc73..90884e2eb1 100644
--- a/doc/posix-functions/fstatat.texi
+++ b/doc/posix-functions/fstatat.texi
@@ -40,5 +40,10 @@ This function does not fail when the second argument is an empty string
 on some platforms, even when @code{AT_EMPTY_PATH} is not used:
 glibc 2.7, Linux 2.6.38.
 @item
+This function sets @code{st_ino} only to the low-order 32 bits of
+the inode number of a socket or pipe, which thus can disagree
+with the @code{st_ino} obtained by @code{fstat}:
+macOS 14.
+@item
 @xref{sys/stat.h}, for general portability problems with @code{struct stat}.
 @end itemize
diff --git a/doc/posix-functions/stat.texi b/doc/posix-functions/stat.texi
index f655451392..8afd3b17bb 100644
--- a/doc/posix-functions/stat.texi
+++ b/doc/posix-functions/stat.texi
@@ -50,6 +50,11 @@ Portability problems not fixed by Gnulib:
 Cygwin's @code{stat} function sometimes sets @code{errno} to @code{EACCES} when
 @code{ENOENT} would be more appropriate.
 @item
+This function sets @code{st_ino} only to the low-order 32 bits of
+the inode number of a socket or pipe, which thus can disagree
+with the @code{st_ino} obtained by @code{fstat}:
+macOS 14.
+@item
 Because of the definition of @code{struct stat}, it is not possible to
 portably replace @code{stat} via an object-like macro.  Therefore,
 expressions such as @code{(islnk ? lstat : stat) (name, buf)} are not
-- 
2.40.1