Submitted By: Jim Gifford (jim at cross-lfs dot org)
Date: 2009-01-04
Initial Package Version: 1.21
Origin: Tar Bug List
Upstream Status: Applied
Description: http://lists.gnu.org/archive/html/bug-tar/2008-12/msg00028.html

diff -Naur tar-1.21.orig/src/buffer.c tar-1.21/src/buffer.c
--- tar-1.21.orig/src/buffer.c	2008-11-30 04:30:29.000000000 -0800
+++ tar-1.21/src/buffer.c	2009-01-04 20:04:57.000000000 -0800
@@ -848,6 +848,8 @@
         flush_archive ();
     }
 
+  sys_drain_input_pipe ();
+
   compute_duration ();
   if (verify_option)
     verify_volume ();
@@ -855,7 +857,7 @@
   if (rmtclose (archive) != 0)
     close_error (*archive_name_cursor);
 
-  sys_wait_for_child (child_pid, hit_eof);
+  sys_wait_for_child (child_pid);
 
   tar_stat_destroy (&current_stat_info);
   if (save_name)
diff -Naur tar-1.21.orig/src/common.h tar-1.21/src/common.h
--- tar-1.21.orig/src/common.h	2008-11-30 04:30:29.000000000 -0800
+++ tar-1.21/src/common.h	2009-01-04 20:04:57.000000000 -0800
@@ -699,7 +699,8 @@
 
 void sys_detect_dev_null_output (void);
 void sys_save_archive_dev_ino (void);
-void sys_wait_for_child (pid_t, bool);
+void sys_drain_input_pipe (void);
+void sys_wait_for_child (pid_t);
 void sys_spawn_shell (void);
 bool sys_compare_uid (struct stat *a, struct stat *b);
 bool sys_compare_gid (struct stat *a, struct stat *b);
diff -Naur tar-1.21.orig/src/system.c tar-1.21/src/system.c
--- tar-1.21.orig/src/system.c	2008-11-30 04:30:30.000000000 -0800
+++ tar-1.21/src/system.c	2009-01-04 20:04:57.000000000 -0800
@@ -1,7 +1,6 @@
 /* System-dependent calls for tar.
 
-   Copyright (C) 2003, 2004, 2005, 2006, 2007,
-   2008 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -52,7 +51,12 @@
 }
 
 void
-sys_wait_for_child (pid_t child_pid, bool eof)
+sys_drain_input_pipe (void)
+{
+}
+
+void
+sys_wait_for_child (pid_t child_pid)
 {
 }
 
@@ -156,8 +160,26 @@
 			 && archive_stat.st_ino == dev_null_stat.st_ino));
 }
 
+/* Manage to fully drain a pipe we might be reading, so to not break it on
+   the producer after the EOF block.  FIXME: one of these days, GNU tar
+   might become clever enough to just stop working, once there is no more
+   work to do, we might have to revise this area in such time.  */
+
+void
+sys_drain_input_pipe (void)
+{
+  size_t r;
+
+  if (access_mode == ACCESS_READ
+      && ! _isrmt (archive)
+      && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
+    while ((r = rmtread (archive, record_start->buffer, record_size)) != 0
+	   && r != SAFE_READ_ERROR)
+      continue;
+}
+
 void
-sys_wait_for_child (pid_t child_pid, bool eof)
+sys_wait_for_child (pid_t child_pid)
 {
   if (child_pid)
     {
@@ -171,11 +193,8 @@
 	  }
 
       if (WIFSIGNALED (wait_status))
-	{
-	  int sig = WTERMSIG (wait_status);
-	  if (!(!eof && sig == SIGPIPE))
-	    ERROR ((0, 0, _("Child died with signal %d"), sig));
-	}
+	ERROR ((0, 0, _("Child died with signal %d"),
+		WTERMSIG (wait_status)));
       else if (WEXITSTATUS (wait_status) != 0)
 	ERROR ((0, 0, _("Child returned status %d"),
 		WEXITSTATUS (wait_status)));
