On GNU/Hurd, the GNU coreutils test test/cp/sparse-to-pipe.sh fails. The
test tries to copy a sparse file to a FIFO. Using 'rpctrace' allowed me
to track down the issue. See the output below:

    $ mkfifo fifo
    $ touch file
    $ timeout -v 10 rpctrace cp file fifo
    [...]
      16<--37(pid8513)->auth_getids () = 0 1000 {1000 1000} {1000 24 25 27 29 
30 44 46 100 102} {1000 1000}
    task20(pid8513)->vm_allocate (0 4 1) = 0 4312129536
    task20(pid8513)->vm_allocate (0 8 1) = 0 4312133632
    task20(pid8513)->vm_allocate (0 40 1) = 0 4314992640
    task20(pid8513)->vm_allocate (0 8 1) = 0 4314996736
      19<--35(pid8513)->dir_lookup ("fifo/" 2097153 0)
    timeout: sending signal TERM to command 'rpctrace'

>From the trailing backslash, I can tell that it is trying to open "fifo"
as a target directory. It seems that Hurd doesn't support O_PATH or
O_SEARCH, so O_RDONLY is used. Here is a test program to confirm:

    $ cat main.c
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    int
    main (void)
    {
      int fd = open ("fifo", O_RDONLY | O_DIRECTORY);
      return 0;
    }

Here is the output on GNU/Linux:

    $ gcc main.c
    $ mkfifo fifo 2>/dev/null;
    $ timeout -v 10 ./a.out; echo $?
    0

Here is the output on GNU/Hurd:

    $ gcc main.c
    $ mkfifo fifo 2>/dev/null;
    $ timeout -v 10 ./a.out; echo $?
    timeout: sending signal TERM to command './a.out'
    124

The POSIX documentation of these flags isn't the most clear, and perhaps
a ticket should be opened to clarify this behavior [1]. However, I
suspect they intended for O_DIRECTORY overrule O_RDONLY when operationg
on FIFOs. I.e., fail immediately since it isn't a directory instead of
waiting for a writer:

    $ strace --quiet=all -P fifo ./a.out; echo $?
    openat(AT_FDCWD, "fifo", O_RDONLY|O_DIRECTORY) = -1 ENOTDIR (Not a 
directory)
    0

We have only seen GNU/Hurd wait for a writer which also backs up that
suspicion. I guess we could add O_NONBLOCK like this:

diff --git a/gl/lib/targetdir.c b/gl/lib/targetdir.c
index 24cff48c3..565c7cd9a 100644
--- a/gl/lib/targetdir.c
+++ b/gl/lib/targetdir.c
@@ -63,7 +63,9 @@ target_directory_operand (char const *file, struct stat *st)
   if (must_be_working_directory (file))
     return AT_FDCWD;
 
-  int fd = open (file, O_PATHSEARCH | O_DIRECTORY);
+  int fd = open (file, (O_PATHSEARCH
+                        | (O_PATHSEARCH == O_RDONLY ? O_NONBLOCK : 0)
+                        | O_DIRECTORY));
 
   /* On platforms lacking O_PATH, using O_SEARCH | O_DIRECTORY to
      open an overly-protected non-directory can fail with either


However, I don't really like the idea of adding flags where it isn't
necessary. It seems harmless here, but there is always a chance some
platform has some quirky behavior when O_NONBLOCK is set.

Pádraig, what do you think about applying the attached patch? It just
adds --no-target-directory, since this isn't the goal of that test
anyway.

Collin

[1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/open.html

>From c3c45ef46ccdef4f78e3e26d0c9a31723927556a Mon Sep 17 00:00:00 2001
Message-ID: <c3c45ef46ccdef4f78e3e26d0c9a31723927556a.1789190432.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Fri, 11 Sep 2026 22:08:11 -0700
Subject: [PATCH] test: cp: avoid a false failure on GNU/Hurd

* tests/cp/sparse-to-pipe.sh: Use 'cp -T' to avoid opening the fifo as a
target directory, which causes GNU/Hurd to wait for a writer.
---
 tests/cp/sparse-to-pipe.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/cp/sparse-to-pipe.sh b/tests/cp/sparse-to-pipe.sh
index 09cebc8bd..fa9dc0982 100755
--- a/tests/cp/sparse-to-pipe.sh
+++ b/tests/cp/sparse-to-pipe.sh
@@ -28,7 +28,7 @@ mkfifo_or_skip_ pipe
 timeout 10 cat pipe > copy & pid=$!
 
 truncate -s1M sparse || framework_failure_
-timeout 10 cp sparse pipe || fail=1
+timeout 10 cp -T sparse pipe || fail=1
 
 # Ensure that the cat has completed before comparing.
 wait $pid
-- 
2.55.0

Reply via email to