X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fpopen.c;h=64a4f619e4f1be2f4209eb9b079cf4d4b247f930;hb=21c3d05ca705daa62ec4c7444e67af48ba757c18;hp=a1f1d45bfd2b06cf3acd48e97cc02a9ea77447e4;hpb=a8f637e3c49275e6789c05d67c1fbd1751e5610a;p=gnulib.git diff --git a/lib/popen.c b/lib/popen.c index a1f1d45bf..64a4f619e 100644 --- a/lib/popen.c +++ b/lib/popen.c @@ -1,5 +1,5 @@ /* Open a stream to a sub-process. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009-2011 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 @@ -18,17 +18,6 @@ #include -/* Get the original definition of popen. It might be defined as a macro. */ -#define __need_FILE -# include -#undef __need_FILE - -static inline FILE * -orig_popen (const char *filename, const char *mode) -{ - return popen (filename, mode); -} - /* Specification. */ #include @@ -37,6 +26,8 @@ orig_popen (const char *filename, const char *mode) #include #include +#undef popen + FILE * rpl_popen (const char *filename, const char *mode) { @@ -56,21 +47,31 @@ 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 - || fcntl (STDIN_FILENO, F_SETFD, - fcntl (STDIN_FILENO, F_GETFD) | FD_CLOEXEC) == -1) - abort (); + || fcntl (STDIN_FILENO, F_SETFD, + fcntl (STDIN_FILENO, F_GETFD) | FD_CLOEXEC) == -1) + abort (); } if (cloexec1 < 0) { if (open ("/dev/null", O_RDONLY) != STDOUT_FILENO - || fcntl (STDOUT_FILENO, F_SETFD, - fcntl (STDOUT_FILENO, F_GETFD) | FD_CLOEXEC) == -1) - abort (); + || fcntl (STDOUT_FILENO, F_SETFD, + 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);