When st_size is not usable, truncate opens the --reference operand and
uses lseek(SEEK_END) to obtain a size.  Opening a FIFO with O_RDONLY
blocks until a writer appears, so "truncate --reference=fifo file"
could hang indefinitely.  Use O_NONBLOCK, matching the existing open of
the output file and the approach taken in df.

Introduced by commit v8.16-49-g9d308df13.

* NEWS: Mention the fix.
* src/truncate.c (main): Open the reference with O_NONBLOCK.
* tests/truncate/truncate-fifo.sh: Also cover --reference=FIFO.

Signed-off-by: Iván Ezequiel Rodriguez <[email protected]>
---
 NEWS                            | 3 +++
 src/truncate.c                  | 3 ++-
 tests/truncate/truncate-fifo.sh | 8 ++++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 67ffc1bf2..946627523 100644
--- a/NEWS
+++ b/NEWS
@@ -58,6 +58,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   with an error.
   [This bug was present in "the beginning".]
 
+  'truncate --reference=R' no longer hangs when R is a FIFO.
+  [bug introduced in coreutils-8.17]
+
   'unexpand -t' no longer overflows a heap buffer, for tab values > 
SIZE_MAX/16,
   or with multi-byte blank characters longer than the tab value.
   [bugs introduced in coreutils-9.11]
diff --git a/src/truncate.c b/src/truncate.c
index 7119132e0..e6c20b70a 100644
--- a/src/truncate.c
+++ b/src/truncate.c
@@ -326,7 +326,8 @@ main (int argc, char **argv)
         file_size = sb.st_size;
       else
         {
-          int ref_fd = open (ref_file, O_RDONLY);
+          /* O_NONBLOCK so we do not hang forever on a FIFO with no writer.  */
+          int ref_fd = open (ref_file, O_RDONLY | O_NONBLOCK);
           if (0 <= ref_fd)
             {
               off_t file_end = lseek (ref_fd, 0, SEEK_END);
diff --git a/tests/truncate/truncate-fifo.sh b/tests/truncate/truncate-fifo.sh
index c456c76ff..9b8a40910 100755
--- a/tests/truncate/truncate-fifo.sh
+++ b/tests/truncate/truncate-fifo.sh
@@ -21,7 +21,15 @@ print_ver_ truncate
 
 mkfifo_or_skip_ fifo
 
+
+# Output FIFO must not hang.
 timeout 10 truncate -s0 fifo
 test "$?" = 124 && fail=1
 
+# Reference FIFO must not hang either.
+touch file || framework_failure_
+timeout 10 truncate --reference=fifo file 2>/dev/null
+test "$?" = 124 && fail=1
+
+
 Exit $fail
-- 
2.43.0




Reply via email to