about summary refs log tree commit diff
path: root/libio
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
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')
-rw-r--r--libio/fileops.c20
-rw-r--r--libio/freopen.c64
-rw-r--r--libio/freopen64.c61
-rw-r--r--libio/libio.h4
-rw-r--r--libio/oldfileops.c9
5 files changed, 121 insertions, 37 deletions
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 <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;
 }
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 <fcntl.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include <fd_to_filename.h>
 
@@ -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 <bothner@cygnus.com>.
 
@@ -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,