diff --git a/ChangeLog b/ChangeLog index 0c0aa6a2ff..1cb8f4fc2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2011-05-15 Ulrich Drepper + * libio/freopen.c (freopen): Don't close old file descriptor + before the new one is opened. Instead dup the new file descriptor + to the old one after the new stream is created. + * libio/freopen64.c (freopen64): Likewise. + * libio/libio.h: Define _IO_FLAGS2_NOCLOSE and _IO_FLAGS2_CLOEXEC. + * libio/fileops.c (_IO_new_file_close_it): Handle new + _IO_FLAGS2_NOCLOSE flag. + (_IO_new_file_fopen): Set _IO_FLAGS2_CLOEXEC for "e" mode. + If _IO_file_open didn't set FD_CLOEXEC do it after the call. + * libio/oldfileops.c (_IO_old_file_close_it): Handle new + _IO_FLAGS2_NOCLOSE flag. + * include/unistd.h: Add hidden_proto for dup3. + Define __have_dup3. + * io/dup3.c: Define hidden symbol. + * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_DUP3. + [BZ #7101] * posix/getopt.c (_getopt_internal_r): List all ambigious possibilities when an incomplete long option is used. diff --git a/include/unistd.h b/include/unistd.h index 0ad2983280..5014e2e772 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -79,6 +79,7 @@ char *__canonicalize_directory_name_internal (__const char *__thisdir, extern int __dup (int __fd); extern int __dup2 (int __fd, int __fd2); libc_hidden_proto (__dup2) +libc_hidden_proto (dup3) extern int __execve (__const char *__path, char *__const __argv[], char *__const __envp[]); extern long int __pathconf (__const char *__path, int __name); @@ -175,6 +176,7 @@ extern int __have_sock_cloexec; SOCK_CLOEXEC. Avoid defining separate variables for all of them unless it is really necessary. */ #define __have_pipe2 __have_sock_cloexec +#define __have_dup3 __have_sock_cloexec extern int __getlogin_r_loginuid (char *name, size_t namesize) attribute_hidden; diff --git a/io/dup3.c b/io/dup3.c index 162ab4e68b..17bc88a018 100644 --- a/io/dup3.c +++ b/io/dup3.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 Free Software Foundation, Inc. +/* Copyright (C) 2008, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -43,6 +43,7 @@ dup3 (fd, fd2, flags) __set_errno (ENOSYS); return -1; } +libc_hidden_def (dup3) stub_warning (dup3) #include diff --git a/libio/fileops.c b/libio/fileops.c index 343afa68b5..2b696ab1e0 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -180,7 +180,8 @@ _IO_new_file_close_it (fp) INTUSE(_IO_unsave_markers) (fp); - int close_status = _IO_SYSCLOSE (fp); + int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0 + ? _IO_SYSCLOSE (fp) : 0); /* Free buffer. */ #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T @@ -328,11 +329,12 @@ _IO_new_file_fopen (fp, filename, mode, is32not64) case 'c': fp->_flags2 |= _IO_FLAGS2_NOTCANCEL; continue; -#ifdef O_CLOEXEC case 'e': +#ifdef O_CLOEXEC oflags |= O_CLOEXEC; - continue; #endif + fp->_flags2 |= _IO_FLAGS2_CLOEXEC; + continue; default: /* Ignore. */ continue; @@ -343,6 +345,18 @@ _IO_new_file_fopen (fp, filename, mode, is32not64) result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write, is32not64); +#ifndef __ASSUME_O_CLOEXEC + if ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 && __have_o_cloexec <= 0) + { + if (__have_o_cloexec == 0) + { + int flags = __fcntl (fd, F_GETFD); + __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1; + } + if (__have_o_cloexec < 0) + __fcntl (fd, F_SETFD, FD_CLOEXEC); + } +#endif #ifdef _LIBC if (result != NULL) diff --git a/libio/freopen.c b/libio/freopen.c index d80815f918..20eda9d0f5 100644 --- a/libio/freopen.c +++ b/libio/freopen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993,95,96,97,98,2000,2001,2002,2003,2008 +/* Copyright (C) 1993,95,96,97,98,2000,2001,2002,2003,2008,2011 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -28,7 +28,9 @@ #include "libioP.h" #include "stdio.h" +#include #include +#include #include #include @@ -40,17 +42,14 @@ freopen (filename, mode, fp) FILE* fp; { FILE *result; - int fd = -1; CHECK_FILE (fp, NULL); if (!(fp->_flags & _IO_IS_FILEBUF)) return NULL; _IO_acquire_lock (fp); - if (filename == NULL && _IO_fileno (fp) >= 0) - { - fd = __dup (_IO_fileno (fp)); - if (fd != -1) - filename = fd_to_filename (fd); - } + int fd = _IO_fileno (fp); + const char *gfilename = (filename == NULL && fd >= 0 + ? fd_to_filename (fd) : filename); + fp->_flags2 |= _IO_FLAGS2_NOCLOSE; #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) if (&_IO_stdin_used == NULL) { @@ -61,7 +60,7 @@ freopen (filename, mode, fp) up here. */ _IO_old_file_close_it (fp); _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_old_file_jumps; - result = _IO_old_file_fopen (fp, filename, mode); + result = _IO_old_file_fopen (fp, gfilename, mode); } else #endif @@ -70,18 +69,53 @@ freopen (filename, mode, fp) _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps; if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL) fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; - result = INTUSE(_IO_file_fopen) (fp, filename, mode, 1); + result = INTUSE(_IO_file_fopen) (fp, gfilename, mode, 1); if (result != NULL) result = __fopen_maybe_mmap (result); } + fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; if (result != NULL) - /* unbound stream orientation */ - result->_mode = 0; - if (fd != -1) { - __close (fd); - free ((char *) filename); + /* unbound stream orientation */ + result->_mode = 0; + + if (fd != -1) + { +#ifdef O_CLOEXEC +# ifndef __ASSUME_DUP3 + int newfd; + if (__have_dup3 < 0) + newfd = -1; + else + newfd = +# endif + dup3 (_IO_fileno (result), fd, + (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 + ? O_CLOEXEC : 0); +#else +# define newfd 1 +#endif + +#ifndef __ASSUME_DUP3 + if (newfd < 0) + { + if (errno == ENOSYS) + __have_dup3 = -1; + + dup2 (_IO_fileno (result), fd); + if ((result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0) + __fcntl (fd, F_SETFD, FD_CLOEXEC); + } +#endif + __close (_IO_fileno (result)); + _IO_fileno (result) = fd; + } } + else if (fd != -1) + __close (fd); + if (filename == NULL) + free ((char *) gfilename); + _IO_release_lock (fp); return result; } diff --git a/libio/freopen64.c b/libio/freopen64.c index 2dad6d7b4e..99045c6419 100644 --- a/libio/freopen64.c +++ b/libio/freopen64.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993,1995,1996,1997,1998,2000,2001,2002, 2003, 2008 +/* Copyright (C) 1993,1995,1996,1997,1998,2000,2001,2002, 2003, 2008, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -28,7 +28,9 @@ #include "libioP.h" #include "stdio.h" +#include #include +#include #include @@ -40,32 +42,63 @@ freopen64 (filename, mode, fp) { #ifdef _G_OPEN64 FILE *result; - int fd = -1; CHECK_FILE (fp, NULL); if (!(fp->_flags & _IO_IS_FILEBUF)) return NULL; _IO_acquire_lock (fp); - if (filename == NULL && _IO_fileno (fp) >= 0) - { - fd = __dup (_IO_fileno (fp)); - if (fd != -1) - filename = fd_to_filename (fd); - } + int fd = _IO_fileno (fp); + const char *gfilename = (filename == NULL && fd >= 0 + ? fd_to_filename (fd) : filename); + fp->_flags2 |= _IO_FLAGS2_NOCLOSE; INTUSE(_IO_file_close_it) (fp); _IO_JUMPS ((struct _IO_FILE_plus *) fp) = &_IO_file_jumps; if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL) fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; - result = INTUSE(_IO_file_fopen) (fp, filename, mode, 0); + result = INTUSE(_IO_file_fopen) (fp, gfilename, mode, 0); + fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; if (result != NULL) result = __fopen_maybe_mmap (result); if (result != NULL) - /* unbound stream orientation */ - result->_mode = 0; - if (fd != -1) { - __close (fd); - free ((char *) filename); + /* unbound stream orientation */ + result->_mode = 0; + + if (fd != -1) + { +#ifdef O_CLOEXEC +# ifndef __ASSUME_DUP3 + int newfd; + if (__have_dup3 < 0) + newfd = -1; + else + newfd = +# endif + dup3 (_IO_fileno (result), fd, + (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 + ? O_CLOEXEC : 0); +#else +# define newfd 1 +#endif + +#ifndef __ASSUME_DUP3 + if (newfd < 0) + { + if (errno == ENOSYS) + __have_dup3 = -1; + + dup2 (_IO_fileno (result), fd); + if ((result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0) + __fcntl (fd, F_SETFD, FD_CLOEXEC); + } +#endif + __close (_IO_fileno (result)); + _IO_fileno (result) = fd; + } } + else if (fd != -1) + __close (fd); + if (filename == NULL) + free ((char *) gfilename); _IO_release_lock (fp); return result; #else diff --git a/libio/libio.h b/libio/libio.h index 3c9f2bd3e8..bebc112a3b 100644 --- a/libio/libio.h +++ b/libio/libio.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-1995,1997-2006,2007,2009 Free Software Foundation, Inc. +/* Copyright (C) 1991-1995,1997-2006,2007,2009,2011 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Per Bothner . @@ -145,6 +145,8 @@ #define _IO_FLAGS2_USER_WBUF 8 #ifdef _LIBC # define _IO_FLAGS2_SCANF_STD 16 +# define _IO_FLAGS2_NOCLOSE 32 +# define _IO_FLAGS2_CLOEXEC 64 #endif /* These are "formatting flags" matching the iostream fmtflags enum values. */ diff --git a/libio/oldfileops.c b/libio/oldfileops.c index be99a2500c..3e3daa8ae1 100644 --- a/libio/oldfileops.c +++ b/libio/oldfileops.c @@ -155,7 +155,8 @@ _IO_old_file_close_it (fp) INTUSE(_IO_unsave_markers) (fp); - close_status = _IO_SYSCLOSE (fp); + close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0 + ? _IO_SYSCLOSE (fp) : 0); /* Free buffer. */ INTUSE(_IO_setb) (fp, NULL, NULL, 0); @@ -676,7 +677,7 @@ _IO_old_file_write (f, data, n) { f->_flags |= _IO_ERR_SEEN; break; - } + } to_do -= count; data = (void *) ((char *) data + count); } @@ -763,12 +764,12 @@ _IO_old_file_xsputn (f, data, n) do_write = to_do - (block_size >= 128 ? to_do % block_size : 0); if (do_write) - { + { count = old_do_write (f, s, do_write); to_do -= count; if (count < do_write) return n - to_do; - } + } /* Now write out the remainder. Normally, this will fit in the buffer, but it's somewhat messier for line-buffered files, diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index c220dca947..d78f1015d3 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -1,6 +1,6 @@ /* Set flags signalling availability of kernel features based on given kernel version number. - Copyright (C) 1999-2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1999-2009, 2010, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -496,6 +496,7 @@ # define __ASSUME_PIPE2 1 # define __ASSUME_EVENTFD2 1 # define __ASSUME_SIGNALFD4 1 +# define __ASSUME_DUP3 1 #endif /* Support for the accept4 syscall was added in 2.6.28. */