Close stdin/out after child is forked

Testcase:

{ sleep 1; yes | head -n99999; } | strace -o/dev/null sh -c 'exec <&-; sleep 9'

The writer (head) will be able to perform writes to write end of the pipe.
With strace call removed, head will immediately get SIGPIPE.

This change fixes this: now writer immediately gets SIGPIPE with strace too.

* strace.c (startup_child): Close stdin/out and reopen them to /dev/null.

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
diff --git a/strace.c b/strace.c
index 614b85f..35a0423 100644
--- a/strace.c
+++ b/strace.c
@@ -1353,6 +1353,27 @@
 		 * to create a genuine separate stack and execute on it.
 		 */
 	}
+	/*
+	 * A case where straced process is part of a pipe:
+	 * { sleep 1; yes | head -n99999; } | strace -o/dev/null sh -c 'exec <&-; sleep 9'
+	 * If strace won't close its fd#0, closing it in tracee is not enough:
+	 * the pipe is still open, it has a reader. Thus, "head" will not get its
+	 * SIGPIPE at once, on the first write.
+	 *
+	 * Preventing it by closing strace's stdin/out.
+	 * (Don't leave fds 0 and 1 closed, this is bad practice: future opens
+	 * will reuse them, unexpectedly making a newly opened object "stdin").
+	 */
+	close(0);
+	if (open("/dev/null", O_RDWR) != 0) /* /dev not populated? */
+		if (open("/", O_RDONLY) != 0) /* shouldn't happen... */
+			perror_msg_and_die("Can't open '/'");
+	dup2(0, 1);
+#if 0
+	/* A good idea too, but we sometimes need to print error messages */
+	if (shared_log != stderr)
+		dup2(0, 2);
+#endif
 }
 
 #if USE_SEIZE