diff options
author | Eric Blake <ebb9@byu.net> | 2009-08-19 07:15:54 -0600 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2009-08-19 07:42:30 -0600 |
commit | a8f637e3c49275e6789c05d67c1fbd1751e5610a (patch) | |
tree | c8a9a99c67133a009a59149dcc7b15e680ec1c1a /lib/popen.c | |
parent | 3ef64012bf653379fda629f5a6b619be4c1f2e69 (diff) | |
download | gnulib-a8f637e3c49275e6789c05d67c1fbd1751e5610a.tar.gz |
popen: fix cygwin 1.5 bug when stdin closed
* doc/posix-functions/popen.texi (popen): Document cygwin bugs.
* modules/popen: New file.
* modules/popen-tests: Likewise.
* tests/test-popen.c: Likewise.
* m4/popen.m4: Likewise.
* lib/popen.c: Likewise.
* lib/stdio.in.h (popen): New declaration.
* m4/stdio_h.m4 (gl_STDIO_H_DEFAULTS): Add popen.
* modules/stdio (Makefile.am): Likewise.
* MODULES.html.sh (systems lacking POSIX:2008): Mention it.
Signed-off-by: Eric Blake <ebb9@byu.net>
Diffstat (limited to 'lib/popen.c')
-rw-r--r-- | lib/popen.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/lib/popen.c b/lib/popen.c new file mode 100644 index 0000000000..a1f1d45bfd --- /dev/null +++ b/lib/popen.c @@ -0,0 +1,81 @@ +/* Open a stream to a sub-process. + Copyright (C) 2009 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 Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#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> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +FILE * +rpl_popen (const char *filename, const char *mode) +{ + /* The mingw popen works fine, and all other platforms have fcntl. + The bug of the child clobbering its own file descriptors if stdin + or stdout was closed in the parent can be worked around by + opening those two fds as close-on-exec to begin with. */ + /* Cygwin 1.5.x also has a bug where the popen fd is improperly + marked close-on-exec, and if the application undoes this, then + the fd leaks into subsequent popen calls. We could work around + this by maintaining a list of all fd's opened by popen, and + temporarily marking them cloexec around the real popen call, but + we would also have to override pclose, and the bookkeepping seems + extreme given that cygwin 1.7 no longer has the bug. */ + FILE *result; + int cloexec0 = fcntl (STDIN_FILENO, F_GETFD); + int cloexec1 = fcntl (STDOUT_FILENO, F_GETFD); + int saved_errno; + + 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 (); + } + 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 (); + } + result = orig_popen (filename, mode); + saved_errno = errno; + if (cloexec0 < 0) + close (STDIN_FILENO); + if (cloexec1 < 0) + close (STDOUT_FILENO); + errno = saved_errno; + return result; +} |