When reading from a pipe, cpio exits immediately after encountering
the TRAILER!!! record without consuming any remaining data.  If the
writer has more data to send (e.g. block padding), it receives
SIGPIPE.

This is observed in practice with rpm2cpio (which uses libarchive to
produce cpio archives).  libarchive pads the final block to 10240
bytes, leaving data in the pipe after the TRAILER record.  Under
certain conditions (e.g. small pipe buffer, system under load), cpio
exits before the writer finishes, causing the pipeline to fail with
SIGPIPE.

Fix by reading and discarding remaining input after the TRAILER
record, but only for non-device inputs (pipes, regular files) where
this is safe.  Tape and other special device inputs are excluded, as
reading past the end of an archive could have unwanted side effects.

* src/copyin.c (process_copy_in): Drain remaining input after
the TRAILER record for non-special inputs.
---
 src/copyin.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/copyin.c b/src/copyin.c
index 46d5503..9624e66 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -1594,6 +1594,19 @@ process_copy_in (void)
   if (dot_flag)
     fputc ('\n', stderr);
 
+  /* Drain any remaining input after the TRAILER record.  Archive
+     writers may pad the output beyond the TRAILER (e.g., libarchive
+     pads to a 10240-byte block boundary when writing to a pipe).
+     If we exit without consuming that data, the writer gets SIGPIPE.
+     Skip this for tape/device inputs where reading past the end of
+     an archive could have unwanted side effects.  */
+  if (!input_is_special)
+    {
+      char buf[4096];
+      while (read (in_file_des, buf, sizeof buf) > 0)
+        ;
+    }
+
   replace_symlink_placeholders ();
   apply_delayed_set_stat ();
 
-- 
2.55.0


Reply via email to