about summary refs log tree commit diff
path: root/libio/freopen.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-05-15 15:28:46 -0400
committerUlrich Drepper <drepper@gmail.com>2011-05-15 15:28:46 -0400
commit94b7cc3711b0b74c1d3ae18b9a2e019e51a8e0bf (patch)
tree2ddc8ca200024ecca3faf0f2efffaea15e21a04f /libio/freopen.c
parentbd25564e1e98910ed69043ed6a6f884ce60e5780 (diff)
downloadglibc-94b7cc3711b0b74c1d3ae18b9a2e019e51a8e0bf.tar.gz
glibc-94b7cc3711b0b74c1d3ae18b9a2e019e51a8e0bf.tar.xz
glibc-94b7cc3711b0b74c1d3ae18b9a2e019e51a8e0bf.zip
Fix a few problems in fopen and freopen
fopen should set the FD_CLOEXEC flag if requested evenif the kernel does
not support an aotmic operation.

freopen should reuse the file descriptor for the stream.  This is
especially important for calls to change the standard streams (stin,
stdout, stderr).
Diffstat (limited to 'libio/freopen.c')
-rw-r--r--libio/freopen.c64
1 files changed, 49 insertions, 15 deletions
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 <fcntl.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include <shlib-compat.h>
 #include <fd_to_filename.h>
@@ -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;
 }