popen: simplify access to original popen
authorEric Blake <ebb9@byu.net>
Fri, 21 Aug 2009 00:14:41 +0000 (18:14 -0600)
committerEric Blake <ebb9@byu.net>
Fri, 21 Aug 2009 00:16:36 +0000 (18:16 -0600)
* lib/popen.c (rpl_popen): No need to worry about popen being a
macro.
Reported by Bruno Haible.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
lib/popen.c

index 23a923828b4b68dd25c8020b7ac18dcdcbf70315..580212cd48a12e17192a5711996932e83f914cab 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-08-21  Eric Blake  <ebb9@byu.net>
+
+       popen: simplify access to original popen
+       * lib/popen.c (rpl_popen): No need to worry about popen being a
+       macro.
+       Reported by Bruno Haible.
+
 2009-08-20  Eric Blake  <ebb9@byu.net>
 
        build: avoid some compiler warnings
index a1f1d45bfd2b06cf3acd48e97cc02a9ea77447e4..92a8050fdb803a851d0e62b0bfac12c9ff427e4f 100644 (file)
 
 #include <config.h>
 
-/* Get the original definition of popen.  It might be defined as a macro.  */
-#define __need_FILE
-# include <stdio.h>
-#undef __need_FILE
-
-static inline FILE *
-orig_popen (const char *filename, const char *mode)
-{
-  return popen (filename, mode);
-}
-
 /* Specification.  */
 #include <stdio.h>
 
@@ -37,6 +26,8 @@ orig_popen (const char *filename, const char *mode)
 #include <stdlib.h>
 #include <unistd.h>
 
+#undef popen
+
 FILE *
 rpl_popen (const char *filename, const char *mode)
 {
@@ -56,6 +47,15 @@ rpl_popen (const char *filename, const char *mode)
   int cloexec1 = fcntl (STDOUT_FILENO, F_GETFD);
   int saved_errno;
 
+  /* If either stdin or stdout was closed (that is, fcntl failed),
+     then we open a dummy close-on-exec fd to occupy that slot.  That
+     way, popen's internal use of pipe() will not contain either fd 0
+     or 1, overcoming the fact that the child process blindly calls
+     close() on the parent's end of the pipe without first checking
+     whether it is clobbering the fd just placed there via dup2(); the
+     exec will get rid of the dummy fd's in the child.  Fortunately,
+     closed stderr in the parent does not cause problems in the
+     child.  */
   if (cloexec0 < 0)
     {
       if (open ("/dev/null", O_RDONLY) != STDIN_FILENO
@@ -70,7 +70,8 @@ rpl_popen (const char *filename, const char *mode)
                    fcntl (STDOUT_FILENO, F_GETFD) | FD_CLOEXEC) == -1)
        abort ();
     }
-  result = orig_popen (filename, mode);
+  result = popen (filename, mode);
+  /* Now, close any dummy fd's created in the parent.  */
   saved_errno = errno;
   if (cloexec0 < 0)
     close (STDIN_FILENO);