Pádraig Brady <[email protected]> writes:

> We could avoid this in the test at least like:
>
>   test $(src/stat -L -c%i /dev/stdin) = \
>        $(src/stat -L -c%i - </dev/stdin) ||
>    skip_ '/dev/stdin correlation mismatch'

Interestingly, this check didn't work for me on macOS 26.4.1 (cfarm104).

> Note this is kind of like https://bugs.gnu.org/35713
> and DEV_FD_MIGHT_BE_CHR is set on FreeBSD,
> so perhaps we could do open()+fstat() in follow_fstatat()?

I have a patch locally that does this and it seems to work. I would
prefer not calling open when not necessary though, i.e., on platforms
where things behave as expected. The issue I am running into is writing
an Autoconf test. See the following program which does not show the bug:

    $ cat main.c 
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <inttypes.h>
    #include <unistd.h>
    #include <fcntl.h>
    int
    main (void)
    {
      struct stat st1;
      if (stat ("/dev/stdin", &st1) < 0)
        abort ();
      printf ("%jd %jd\n", (intmax_t) st1.st_dev, (intmax_t) st1.st_ino);
      struct stat st2;
      int fd = open ("/dev/stdin", O_RDONLY);
      if (fd < 0 || fstat (fd, &st2) < 0)
        abort ();
      printf ("%jd %jd\n", (intmax_t) st2.st_dev, (intmax_t) st2.st_ino);
      return 0;
    }
    $ gcc main.c && ./a.out 
    1977778751 9141
    1977778751 9141

Hopefully I am just missing something silly, or perhaps it is not even
worth the effort and using "#ifdef __APPLE__" is enough.

I attached another patch that "works" (passes all tests), but calling
stat with a file descriptor open seems like asking for trouble.
Therefore, I prefer your idea.

Collin

>From 800f72242362163853514a352c777d8995a7d152 Mon Sep 17 00:00:00 2001
Message-ID: <800f72242362163853514a352c777d8995a7d152.1780638254.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Thu, 4 Jun 2026 22:33:57 -0700
Subject: [PATCH] install: workaround a macOS bug that prevents reading
 standard input

* src/copy.c (copy_reg): On macOS, check a second stat call if fstat and
stat give different dev/ino pairs.
* tests/install/stdin.sh: Remove the skip condition added in commit
2632fbf08 (tests: install: avoid failure on FreeBSD/macOS, 2026-06-03).
Fixes https://bugs.gnu.org/70411
---
 src/copy.c             | 13 +++++++++++--
 tests/install/stdin.sh |  5 -----
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/copy.c b/src/copy.c
index a53fb8f8c..7ae14cc7b 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -763,8 +763,17 @@ copy_reg (char const *src_name, char const *dst_name,
     }
 
   /* Compare the source dev/ino from the open file to the incoming,
-     saved ones obtained via a previous call to stat.  */
-  if (! psame_inode (src_sb, &src_open_sb))
+     saved ones obtained via a previous call to stat.
+     Work around a macOS bug where stat and fstat give us a different dev/ino.
+     See the following threads:
+     <https://bugs.gnu.org/70411>
+     <https://lists.gnu.org/r/coreutils/2026-06/msg00004.html>.  */
+  if (! psame_inode (src_sb, &src_open_sb)
+#ifdef __APPLE__
+      && ((x->dereference == DEREF_NEVER ? lstat : stat) (src_name, &src_open_sb) < 0
+          || ! psame_inode (src_sb, &src_open_sb))
+#endif
+     )
     {
       error (0, 0,
              _("skipping file %s, as it was replaced while being copied"),
diff --git a/tests/install/stdin.sh b/tests/install/stdin.sh
index 2e050059e..4ee8a85c9 100755
--- a/tests/install/stdin.sh
+++ b/tests/install/stdin.sh
@@ -26,11 +26,6 @@ tty=$(readlink -f /dev/stdin)
 test -r "$tty" 2>&1 \
   || skip_ '/dev/stdin is not readable'
 
-# work around FreeBSD / macOS issue as discussed at:
-# https://lists.gnu.org/r/coreutils/2026-06/msg00004.html
-test $(stat -L -c%i /dev/stdin) = $(stat -L -c%i - </dev/stdin) ||
-  skip_ '/dev/stdin inode correlation mismatch'
-
 echo a >a || framework_failure_
 echo b >b || framework_failure_
 
-- 
2.54.0

Reply via email to