On 12/09/2026 06:22, Collin Funk wrote:
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

Nice investigation.

That's fine and good to push,
but please change the "test:" to "tests:" in the summary.

thanks!
Padraig

Reply via email to