From nobody@FreeBSD.org  Fri Jun 22 09:42:31 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 49F07106566C
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 22 Jun 2012 09:42:31 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 34EE18FC12
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 22 Jun 2012 09:42:31 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q5M9gUeH020473
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 22 Jun 2012 09:42:30 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q5M9gTCj020472;
	Fri, 22 Jun 2012 09:42:29 GMT
	(envelope-from nobody)
Message-Id: <201206220942.q5M9gTCj020472@red.freebsd.org>
Date: Fri, 22 Jun 2012 09:42:29 GMT
From: Jukka Ukkonen <jau@iki.fi>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Enhancement to allow fopen() to set O_CLOEXEC for open()
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         169320
>Category:       kern
>Synopsis:       [libc] [patch] Enhancement to allow fopen() to set O_CLOEXEC for open()
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    jilles
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jun 22 09:50:01 UTC 2012
>Closed-Date:    Sun Nov 03 19:36:20 UTC 2013
>Last-Modified:  Sun Nov 03 19:36:20 UTC 2013
>Originator:     Jukka Ukkonen
>Release:        FreeBSD 9.0-STABLE
>Organization:
-----
>Environment:
FreeBSD sleipnir 9.0-STABLE FreeBSD 9.0-STABLE #0: Fri Jun 22 10:54:06 EEST 2012     root@sleipnir:/usr/obj/usr/src/sys/Sleipnir  amd64
>Description:
This is a change request to allow a clean approach to fixing a short time window
between fopen() and fcntl() to set FD_CLOEXEC.
In threaded applications another thread could call exec() during that time
causing the newly created file descriptor to leak to the child program.

There is a lot of code with logic like...

fp = fopen (...);
..
fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);

The currently existing alternative to plug this potential leak is change
the code to this method...

fd = open (..., O_CLOEXEC);
..
fp = fdopen (fd, ...);

Anyhow this leave the code still at least as hairy as the previous model using
a separate call to set FD_CLOEXEC.

A cleaner method would be extending the fopen() to allow a new mode character
as a companion to O_CLOEXEC flag for open().
FreeBSD already includes support for setting O_EXCL through the "x" mode
identifier. It would definitely not hurt adding a "c" mode character to
automatically set the file descriptor close-on-exec marker inside fopen().

With this approach the original code using fopen() & fcntl() could be
reduced to

fp = fopen (..., "...c");

to set the close-on-exec mark atomically inside open().

This would make the resulting code much cleaner wherever the close-on-exec
feature is needed.
The code would become also a bit less error prone because the flagging for
automatic close would be done in a centralized manner for all callers of
fopen().

While this change has been neither merged nor declined it does not make
sense to try to actively plug the little time windows for potential file
descriptor leaks to child programs.
==> Thus classification to serious/high.

>How-To-Repeat:
See the full description above.
>Fix:
Find attached a patch to implement the proposed change.

Patch attached with submission follows:

--- /usr/src/lib/libc/stdio/flags.c.orig	2012-06-22 09:25:12.000000000 +0300
+++ /usr/src/lib/libc/stdio/flags.c	2012-06-22 09:41:06.000000000 +0300
@@ -80,28 +80,43 @@
 		return (0);
 	}
 
-	/* 'b' (binary) is ignored */
-	if (*mode == 'b')
-		mode++;
+	/*
+	 * Because the order may not be universally deterministic,
+	 * we are liberal and accept the add-on flags in any order.
+	 */
 
-	/* [rwa][b]\+ means read and write */
-	if (*mode == '+') {
-		mode++;
-		ret = __SRW;
-		m = O_RDWR;
-	}
+	while (*mode) {
+		switch (*mode) {
+		case 'b':
+			/* 'b' (binary) is ignored */
+			break;
 
-	/* 'b' (binary) can appear here, too -- and is ignored again */
-	if (*mode == 'b')
-		mode++;
+		case '+':
+			/* [rwa][b]\+ means read and write */
+			ret = __SRW;
+			m = O_RDWR;
+			break;
 
-	/* 'x' means exclusive (fail if the file exists) */
-	if (*mode == 'x') {
-		if (m == O_RDONLY) {
-			errno = EINVAL;
-			return (0);
+		case 'x':
+			/* 'x' means exclusive (fail if the file exists) */
+			if (m == O_RDONLY) {
+				errno = EINVAL;
+				return (0);
+			}
+			o |= O_EXCL;
+			break;
+
+		case 'c':
+			/* Set the close-on-exec mark. */
+			o |= O_CLOEXEC;
+			break;
+
+		default:
+			/* We silently ignore what we do not know. */
+			break;
 		}
-		o |= O_EXCL;
+
+		mode++;
 	}
 
 	*optr = m | o;
--- /usr/src/lib/libc/stdio/fopen.3.orig	2012-06-22 09:48:42.000000000 +0300
+++ /usr/src/lib/libc/stdio/fopen.3	2012-06-22 10:03:27.000000000 +0300
@@ -109,6 +109,22 @@
 .St -isoC
 and has no effect; the ``b'' is ignored.
 .Pp
+If the 
+.Fa mode
+string contains a flag
+.Dq Li c
+the file will be automatically closed when 
+.Fn exec
+is called.
+This is a FreeBSD extension and companion to the O_CLOEXEC flag for 
+.Fn open .
+This is a nifty tool for making code like system libraries more stable,
+but it also risks breaking the portability of code to other systems.
+There is no guarantee how other systems will handle an unspecified
+mode character.
+This implementation tries to be liberal and simply ignores all unknown
+mode characters.
+.Pp
 Any created files will have mode
 .Do Dv S_IRUSR
 \&|


>Release-Note:
>Audit-Trail:

From: "Jukka A. Ukkonen" <jau@oxit.fi>
To: bug-followup@FreeBSD.org, jau@iki.fi
Cc:  
Subject: Re: kern/169320: [libc] [patch] Enhancement to allow fopen() to set
 O_CLOEXEC for open()
Date: Sun, 24 Jun 2012 11:29:49 +0300

 This is a multi-part message in MIME format.
 --------------080303070506080801090202
 Content-Type: multipart/alternative;
  boundary="------------040105000505070101060901"
 
 
 --------------040105000505070101060901
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 
 Hmm... It seems linux and glibc-2.7 were there first...
 
         *c*  (since glibc 2.3.3)
 	      Do not make the open operation, or  subsequent  read  and  write
 	      operations, thread cancellation points.
 
         *e*  (since glibc 2.7)
 	      Open  the  file  with  the*O_CLOEXEC*  flag.  See*open*(2)  <http://www.freebsd.org/cgi/man.cgi?query=open&sektion=2&apropos=0&manpath=SuSE+Linux%2fi386+11.3>  for more
 	      information.
 
 Should FreeBSD maybe follow the same pattern and use 'e' instead of 'c'
 to force O_CLOEXEC for open()?
 
 Personally I find 'e' a somewhat illogical linux-ism in contrast to 'c',
 but because linux and glibc had already used 'c' those folks might be hard
 to convince to change.
 Active drive to heterogeneity would be unwise and only undermine emergence
 of any decent standard.
 Commercial vendors do not seem to support a similar feature yet, or they
 have at least kept it undocumented.
 
 So, I ended up creating a new revision of the patch.
 (This one also properly uses relative paths.)
 
 --jau
 
 
 --------------040105000505070101060901
 Content-Type: text/html; charset=ISO-8859-1
 Content-Transfer-Encoding: 7bit
 
 <html>
   <head>
 
     <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
   </head>
   <body bgcolor="#FFFFFF" text="#000000">
     <pre><tt>
 Hmm... It seems linux and glibc-2.7 were there first...
 
        <b>c</b> (since glibc 2.3.3)
 	      Do not make the open operation, or  subsequent  read  and  write
 	      operations, thread cancellation points.
 
        <b>e</b> (since glibc 2.7)
 	      Open  the  file  with  the <b>O_CLOEXEC</b> flag.  See <a href="http://www.freebsd.org/cgi/man.cgi?query=open&amp;sektion=2&amp;apropos=0&amp;manpath=SuSE+Linux%2fi386+11.3"><b>open</b>(2)</a> for more
 	      information.
 
 Should FreeBSD maybe follow the same pattern and use 'e' instead of 'c'
 to force O_CLOEXEC for open()?
 
 Personally I find 'e' a somewhat illogical linux-ism in contrast to 'c',
 but because linux and glibc had already used 'c' those folks might be hard
 to convince to change.
 Active drive to heterogeneity would be unwise and only undermine emergence
 of any decent standard.
 Commercial vendors do not seem to support a similar feature yet, or they
 have at least kept it undocumented.
 
 So, I ended up creating a new revision of the patch.
 (This one also properly uses relative paths.)
 
 --jau
 
 </tt></pre>
   </body>
 </html>
 
 --------------040105000505070101060901--
 
 --------------080303070506080801090202
 Content-Type: text/plain; charset=UTF-8;
  name="fopen-flags-CLOEXEC.patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="fopen-flags-CLOEXEC.patch"
 
 --- lib/libc/stdio/flags.c.orig	2012-01-09 06:59:44.000000000 +0200
 +++ lib/libc/stdio/flags.c	2012-06-24 10:12:16.000000000 +0300
 @@ -80,28 +80,43 @@
  		return (0);
  	}
  
 -	/* 'b' (binary) is ignored */
 -	if (*mode == 'b')
 -		mode++;
 +	/*
 +	 * Because the order may not be universally deterministic,
 +	 * we are liberal and accept the add-on flags in any order.
 +	 */
  
 -	/* [rwa][b]\+ means read and write */
 -	if (*mode == '+') {
 -		mode++;
 -		ret = __SRW;
 -		m = O_RDWR;
 -	}
 +	while (*mode) {
 +		switch (*mode) {
 +		case 'b':
 +			/* 'b' (binary) is ignored */
 +			break;
  
 -	/* 'b' (binary) can appear here, too -- and is ignored again */
 -	if (*mode == 'b')
 -		mode++;
 +		case '+':
 +			/* [rwa][b]\+ means read and write */
 +			ret = __SRW;
 +			m = O_RDWR;
 +			break;
  
 -	/* 'x' means exclusive (fail if the file exists) */
 -	if (*mode == 'x') {
 -		if (m == O_RDONLY) {
 -			errno = EINVAL;
 -			return (0);
 +		case 'x':
 +			/* 'x' means exclusive (fail if the file exists) */
 +			if (m == O_RDONLY) {
 +				errno = EINVAL;
 +				return (0);
 +			}
 +			o |= O_EXCL;
 +			break;
 +
 +		case 'e':
 +			/* Set the close-on-exec mark. */
 +			o |= O_CLOEXEC;
 +			break;
 +
 +		default:
 +			/* We silently ignore what we do not know. */
 +			break;
  		}
 -		o |= O_EXCL;
 +
 +		mode++;
  	}
  
  	*optr = m | o;
 --- lib/libc/stdio/fopen.3.orig	2012-01-09 06:59:44.000000000 +0200
 +++ lib/libc/stdio/fopen.3	2012-06-24 11:15:44.000000000 +0300
 @@ -97,6 +97,12 @@
  causes the
  .Fn fopen
  call to fail if the file already exists.
 +The mode character
 +.Dq Li x
 +is a non-standard FreeBSD extension and a companion to the
 +.Dq O_EXCL
 +flag for
 +.Fn open .
  .Pp
  The
  .Fa mode
 @@ -109,6 +115,29 @@
  .St -isoC
  and has no effect; the ``b'' is ignored.
  .Pp
 +If the 
 +.Fa mode
 +string contains an optional character
 +.Dq Li e
 +the file will be automatically closed when 
 +.Fn exec
 +is called.
 +This is a non-standard FreeBSD extension and companion to the
 +.Dq O_CLOEXEC
 +flag for 
 +.Fn open .
 +This is a handy tool for making code like system libraries more stable,
 +but it also risks breaking the portability of code to other systems.
 +There is no guarantee how other systems will handle a non-standard
 +mode character.
 +This implementation tries to be liberal and simply ignores all unknown
 +mode characters.
 +Linux knows both
 +.Dq Li x
 +and
 +.Dq Li e
 +mode characters and their semantics are similar to FreeBSD.
 +.Pp
  Any created files will have mode
  .Do Dv S_IRUSR
  \&|
 
 --------------080303070506080801090202--

From: Jilles Tjoelker <jilles@stack.nl>
To: bug-followup@FreeBSD.org, jau@iki.fi
Cc:  
Subject: Re: kern/169320: [libc] [patch] Enhancement to allow fopen() to set
 O_CLOEXEC for open()
Date: Wed, 7 Nov 2012 23:16:22 +0100

 --bg08WKrSYDhXBjb5
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Although the new fopen() flag can be emulated via
 open(O_CLOEXEC)/fdopen() as done in lib/libc/gen/fstab.c, I don't like
 having that complication all over libc.
 
 I have written a patch almost entirely from scratch, though. I think
 blindly accepting any order restricts future possibilities too much
 (perhaps we want to put key/value pairs in the mode string at some
 point, for example) and not necessary. C11 is very clear that the 'x'
 option must come after any '+' or 'b' options. I decided that the 'e'
 option must come after any '+, 'b' or 'x' options.
 
 I also added code to use the 'e' option for freopen() and fdopen().
 
 -- 
 Jilles Tjoelker
 
 --bg08WKrSYDhXBjb5
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="stdio-cloexec.patch"
 
 Index: lib/libc/stdio/fdopen.c
 ===================================================================
 --- lib/libc/stdio/fdopen.c	(revision 240561)
 +++ lib/libc/stdio/fdopen.c	(working copy)
 @@ -77,6 +77,8 @@
  		errno = EINVAL;
  		return (NULL);
  	}
 +	if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
 +		return (NULL);
  
  	if ((fp = __sfp()) == NULL)
  		return (NULL);
 Index: lib/libc/stdio/flags.c
 ===================================================================
 --- lib/libc/stdio/flags.c	(revision 240561)
 +++ lib/libc/stdio/flags.c	(working copy)
 @@ -97,6 +97,7 @@
  
  	/* 'x' means exclusive (fail if the file exists) */
  	if (*mode == 'x') {
 +		mode++;
  		if (m == O_RDONLY) {
  			errno = EINVAL;
  			return (0);
 @@ -104,6 +105,10 @@
  		o |= O_EXCL;
  	}
  
 +	/* set close-on-exec */
 +	if (*mode == 'e')
 +		o |= O_CLOEXEC;
 +
  	*optr = m | o;
  	return (ret);
  }
 Index: lib/libc/stdio/fopen.3
 ===================================================================
 --- lib/libc/stdio/fopen.3	(revision 242460)
 +++ lib/libc/stdio/fopen.3	(working copy)
 @@ -97,6 +97,14 @@
  causes the
  .Fn fopen
  call to fail if the file already exists.
 +An optional
 +.Dq Li e
 +following the above
 +causes the
 +.Fn fopen
 +call to set the
 +.Dv FD_CLOEXEC
 +flag on the underlying file descriptor.
  .Pp
  The
  .Fa mode
 @@ -144,6 +152,11 @@
  The
  .Dq Li x
  mode option is ignored.
 +If the
 +.Dq Li e
 +mode option is present, the
 +.Dv FD_CLOEXEC
 +flag is set, otherwise it remains unchanged.
  When the stream is closed via
  .Xr fclose 3 ,
  .Fa fildes
 @@ -271,7 +284,11 @@
  with the exception of the
  .Dq Li x
  mode option which conforms to
 -.St -isoC-2011 .
 +.St -isoC-2011
 +and the
 +.Dq Li e
 +mode option which does not conform to any standard
 +but is also supported by glibc.
  The
  .Fn fdopen
  function
 Index: lib/libc/stdio/freopen.c
 ===================================================================
 --- lib/libc/stdio/freopen.c	(revision 240561)
 +++ lib/libc/stdio/freopen.c	(working copy)
 @@ -194,7 +194,8 @@
  	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
  	 */
  	if (wantfd >= 0) {
 -		if (_dup2(f, wantfd) >= 0) {
 +		if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) :
 +		    _dup2(f, wantfd)) >= 0) {
  			(void)_close(f);
  			f = wantfd;
  		} else
 
 --bg08WKrSYDhXBjb5--

From: jau@iki.fi (Jukka A. Ukkonen)
To: jilles@stack.nl (Jilles Tjoelker)
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/169320: [libc] [patch] Enhancement to allow fopen() to set
Date: Thu, 8 Nov 2012 09:39:20 +0200 (EET)

 Quoting Jilles Tjoelker:
 > 
 > Although the new fopen() flag can be emulated via
 > open(O_CLOEXEC)/fdopen() as done in lib/libc/gen/fstab.c, I don't like
 > having that complication all over libc.
 
 Exactly.
 When I started hunting down all those places where O_CLOEXEC would be
 the proper approach I came to the same exact same conclusion.
 There would be a whole lot of pointless complexity due to open()+fdopen()
 being replicated all over the place.
 
 > I have written a patch almost entirely from scratch, though. I think
 > blindly accepting any order restricts future possibilities too much
 > (perhaps we want to put key/value pairs in the mode string at some
 > point, for example) and not necessary. C11 is very clear that the 'x'
 > option must come after any '+' or 'b' options. I decided that the 'e'
 > option must come after any '+, 'b' or 'x' options.
 
 Key value pairs have nothing to do with the order of the flags as
 long as the value always follows the key flag character(s).
 Proper free flow left to right parse would be much more flexible.
 So, I remain a bit suspicious about strict ordering of the flags.
 
 > I also added code to use the 'e' option for freopen() and fdopen().
 
 Splendid.
 
 
 	Cheers,
 		// jau
 .---  ..-  -.-  -.-  .-    .-  .-.-.-    ..-  -.-  -.-  ---  -.  .  -.
   /    Jukka A. Ukkonen,                             Oxit Ltd, Finland
  /__   M.Sc. (sw-eng & cs)                    (Phone) +358-500-606-671
    /   Internet: Jukka.Ukkonen(a)Oxit.Fi
   /    Internet: jau(a)iki.fi
  v
         .---  .-  ..-  ...-.-  ..  -.-  ..  .-.-.-  ..-.  ..
 + + + + My opinions are mine and mine alone, not my employers. + + + +

From: Jilles Tjoelker <jilles@stack.nl>
To: "Jukka A. Ukkonen" <jau@iki.fi>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/169320: [libc] [patch] Enhancement to allow fopen() to set
Date: Tue, 13 Nov 2012 15:53:17 +0100

 On Thu, Nov 08, 2012 at 09:39:20AM +0200, Jukka A. Ukkonen wrote:
 > Quoting Jilles Tjoelker:
 
 > > I have written a patch almost entirely from scratch, though. I think
 > > blindly accepting any order restricts future possibilities too much
 > > (perhaps we want to put key/value pairs in the mode string at some
 > > point, for example) and not necessary. C11 is very clear that the 'x'
 > > option must come after any '+' or 'b' options. I decided that the 'e'
 > > option must come after any '+, 'b' or 'x' options.
 
 > Key value pairs have nothing to do with the order of the flags as
 > long as the value always follows the key flag character(s).
 > Proper free flow left to right parse would be much more flexible.
 > So, I remain a bit suspicious about strict ordering of the flags.
 
 Glibc supports things like fopen("/foo", "r,ccs=utf-8"). Although
 applications should use such a specification only if it is supported, it
 seems wrong nevertheless to interpret all the characters in it as flags.
 
 -- 
 Jilles Tjoelker
State-Changed-From-To: open->patched 
State-Changed-By: jilles 
State-Changed-When: Sat Dec 1 15:32:52 UTC 2012 
State-Changed-Why:  
Implemented in head. 


Responsible-Changed-From-To: freebsd-bugs->jilles 
Responsible-Changed-By: jilles 
Responsible-Changed-When: Sat Dec 1 15:32:52 UTC 2012 
Responsible-Changed-Why:  
I am handling this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=169320 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/169320: commit references a PR
Date: Sun, 27 Oct 2013 21:50:01 +0000 (UTC)

 Author: jilles
 Date: Sun Oct 27 21:49:52 2013
 New Revision: 257229
 URL: http://svnweb.freebsd.org/changeset/base/257229
 
 Log:
   MFC r243731,r255303: libc: Allow setting close-on-exec in fopen/freopen/
   fdopen.
   
   This commit adds a new mode option 'e'.
   
   For freopen() with a non-NULL path argument and fopen(), the close-on-exec
   flag is set iff the 'e' mode option is specified. For freopen() with a NULL
   path argument and fdopen(), the close-on-exec flag is turned on if the 'e'
   mode option is specified and remains unchanged otherwise.
   
   Although the same behaviour for fopen() can be obtained by open(O_CLOEXEC)
   and fdopen(), this needlessly complicates the calling code.
   
   PR:		kern/169320
 
 Added:
   stable/9/tools/regression/lib/libc/stdio/test-fopen.c
      - copied unchanged from r255303, head/tools/regression/lib/libc/stdio/test-fopen.c
   stable/9/tools/regression/lib/libc/stdio/test-fopen.t
      - copied unchanged from r255303, head/tools/regression/lib/libc/stdio/test-fopen.t
 Modified:
   stable/9/lib/libc/stdio/fdopen.c
   stable/9/lib/libc/stdio/flags.c
   stable/9/lib/libc/stdio/fopen.3
   stable/9/lib/libc/stdio/freopen.c
 Directory Properties:
   stable/9/lib/libc/   (props changed)
   stable/9/tools/regression/lib/libc/   (props changed)
 
 Modified: stable/9/lib/libc/stdio/fdopen.c
 ==============================================================================
 --- stable/9/lib/libc/stdio/fdopen.c	Sun Oct 27 21:39:16 2013	(r257228)
 +++ stable/9/lib/libc/stdio/fdopen.c	Sun Oct 27 21:49:52 2013	(r257229)
 @@ -80,6 +80,12 @@ fdopen(fd, mode)
  
  	if ((fp = __sfp()) == NULL)
  		return (NULL);
 +
 +	if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
 +		fp->_flags = 0;
 +		return (NULL);
 +	}
 +
  	fp->_flags = flags;
  	/*
  	 * If opened for appending, but underlying descriptor does not have
 
 Modified: stable/9/lib/libc/stdio/flags.c
 ==============================================================================
 --- stable/9/lib/libc/stdio/flags.c	Sun Oct 27 21:39:16 2013	(r257228)
 +++ stable/9/lib/libc/stdio/flags.c	Sun Oct 27 21:49:52 2013	(r257229)
 @@ -53,7 +53,7 @@ __sflags(mode, optr)
  	const char *mode;
  	int *optr;
  {
 -	int ret, m, o;
 +	int ret, m, o, known;
  
  	switch (*mode++) {
  
 @@ -80,28 +80,34 @@ __sflags(mode, optr)
  		return (0);
  	}
  
 -	/* 'b' (binary) is ignored */
 -	if (*mode == 'b')
 -		mode++;
 -
 -	/* [rwa][b]\+ means read and write */
 -	if (*mode == '+') {
 -		mode++;
 -		ret = __SRW;
 -		m = O_RDWR;
 -	}
 -
 -	/* 'b' (binary) can appear here, too -- and is ignored again */
 -	if (*mode == 'b')
 -		mode++;
 -
 -	/* 'x' means exclusive (fail if the file exists) */
 -	if (*mode == 'x') {
 -		if (m == O_RDONLY) {
 -			errno = EINVAL;
 -			return (0);
 +	do {
 +		known = 1;
 +		switch (*mode++) {
 +		case 'b':
 +			/* 'b' (binary) is ignored */
 +			break;
 +		case '+':
 +			/* [rwa][b]\+ means read and write */
 +			ret = __SRW;
 +			m = O_RDWR;
 +			break;
 +		case 'x':
 +			/* 'x' means exclusive (fail if the file exists) */
 +			o |= O_EXCL;
 +			break;
 +		case 'e':
 +			/* set close-on-exec */
 +			o |= O_CLOEXEC;
 +			break;
 +		default:
 +			known = 0;
 +			break;
  		}
 -		o |= O_EXCL;
 +	} while (known);
 +
 +	if ((o & O_EXCL) != 0 && m == O_RDONLY) {
 +		errno = EINVAL;
 +		return (0);
  	}
  
  	*optr = m | o;
 
 Modified: stable/9/lib/libc/stdio/fopen.3
 ==============================================================================
 --- stable/9/lib/libc/stdio/fopen.3	Sun Oct 27 21:39:16 2013	(r257228)
 +++ stable/9/lib/libc/stdio/fopen.3	Sun Oct 27 21:49:52 2013	(r257229)
 @@ -100,6 +100,14 @@ or
  causes the
  .Fn fopen
  call to fail if the file already exists.
 +An optional
 +.Dq Li e
 +following the above
 +causes the
 +.Fn fopen
 +call to set the
 +.Dv FD_CLOEXEC
 +flag on the underlying file descriptor.
  .Pp
  The
  .Fa mode
 @@ -149,6 +157,11 @@ of the stream must be compatible with th
  The
  .Dq Li x
  mode option is ignored.
 +If the
 +.Dq Li e
 +mode option is present, the
 +.Dv FD_CLOEXEC
 +flag is set, otherwise it remains unchanged.
  When the stream is closed via
  .Xr fclose 3 ,
  .Fa fildes
 @@ -313,6 +326,10 @@ function
  conforms to
  .St -p1003.1-88 .
  The
 +.Dq Li e
 +mode option does not conform to any standard
 +but is also supported by glibc.
 +The
  .Fn fmemopen
  function
  conforms to
 
 Modified: stable/9/lib/libc/stdio/freopen.c
 ==============================================================================
 --- stable/9/lib/libc/stdio/freopen.c	Sun Oct 27 21:39:16 2013	(r257228)
 +++ stable/9/lib/libc/stdio/freopen.c	Sun Oct 27 21:49:52 2013	(r257229)
 @@ -118,6 +118,8 @@ freopen(file, mode, fp)
  			(void) ftruncate(fp->_file, (off_t)0);
  		if (!(oflags & O_APPEND))
  			(void) _sseek(fp, (fpos_t)0, SEEK_SET);
 +		if (oflags & O_CLOEXEC)
 +			(void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC);
  		f = fp->_file;
  		isopen = 0;
  		wantfd = -1;
 @@ -194,7 +196,8 @@ finish:
  	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
  	 */
  	if (wantfd >= 0) {
 -		if (_dup2(f, wantfd) >= 0) {
 +		if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) :
 +		    _dup2(f, wantfd)) >= 0) {
  			(void)_close(f);
  			f = wantfd;
  		} else
 
 Copied: stable/9/tools/regression/lib/libc/stdio/test-fopen.c (from r255303, head/tools/regression/lib/libc/stdio/test-fopen.c)
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ stable/9/tools/regression/lib/libc/stdio/test-fopen.c	Sun Oct 27 21:49:52 2013	(r257229, copy of r255303, head/tools/regression/lib/libc/stdio/test-fopen.c)
 @@ -0,0 +1,113 @@
 +/*-
 + * Copyright (c) 2013 Jilles Tjoelker
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 + * SUCH DAMAGE.
 + */
 +
 +#include <sys/cdefs.h>
 +__FBSDID("$FreeBSD$");
 +
 +#include	<fcntl.h>
 +#include	<stdio.h>
 +#include	<string.h>
 +
 +/*
 + * O_ACCMODE is currently defined incorrectly. This is what it should be.
 + * Various code depends on the incorrect value.
 + */
 +#define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC)
 +
 +static int testnum = 1;
 +
 +static void
 +runtest(const char *fname, const char *mode)
 +{
 +	FILE *fp;
 +	int fd, flags, wantedflags;
 +
 +	fp = fopen(fname, mode);
 +	if (fp == NULL) {
 +		printf("not ok %d - fopen(\"%s\", \"%s\") failed\n",
 +		    testnum++, fname, mode);
 +		printf("not ok %d - FD_CLOEXEC # SKIP\n",
 +		    testnum++);
 +		return;
 +	}
 +	fd = fileno(fp);
 +	if (fd < 0)
 +		printf("not ok %d - fileno() failed\n", testnum++);
 +	else
 +		printf("ok %d - fopen(\"%s\", \"%s\") and fileno() succeeded\n",
 +		    testnum++, fname, mode);
 +	if (fcntl(fd, F_GETFD) == (strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0))
 +		printf("ok %d - FD_CLOEXEC flag correct\n", testnum++);
 +	else
 +		printf("not ok %d - FD_CLOEXEC flag incorrect\n", testnum++);
 +	flags = fcntl(fd, F_GETFL);
 +	if (strchr(mode, '+'))
 +		wantedflags = O_RDWR | (*mode == 'a' ? O_APPEND : 0);
 +	else if (*mode == 'r')
 +		wantedflags = O_RDONLY;
 +	else if (*mode == 'w')
 +		wantedflags = O_WRONLY;
 +	else if (*mode == 'a')
 +		wantedflags = O_WRONLY | O_APPEND;
 +	else
 +		wantedflags = -1;
 +	if (wantedflags == -1)
 +		printf("not ok %d - unrecognized mode\n", testnum++);
 +	else if ((flags & (CORRECT_O_ACCMODE | O_APPEND)) == wantedflags)
 +		printf("ok %d - correct access mode\n", testnum++);
 +	else
 +		printf("not ok %d - incorrect access mode\n", testnum++);
 +	fclose(fp);
 +}
 +
 +/*
 + * Test program for fopen().
 + */
 +int
 +main(int argc, char *argv[])
 +{
 +	printf("1..45\n");
 +	runtest("/dev/null", "r");
 +	runtest("/dev/null", "r+");
 +	runtest("/dev/null", "w");
 +	runtest("/dev/null", "w+");
 +	runtest("/dev/null", "a");
 +	runtest("/dev/null", "a+");
 +	runtest("/dev/null", "re");
 +	runtest("/dev/null", "r+e");
 +	runtest("/dev/null", "we");
 +	runtest("/dev/null", "w+e");
 +	runtest("/dev/null", "ae");
 +	runtest("/dev/null", "a+e");
 +	runtest("/dev/null", "re+");
 +	runtest("/dev/null", "we+");
 +	runtest("/dev/null", "ae+");
 +
 +	return 0;
 +}
 +
 +/* vim:ts=8:cin:sw=8
 + *  */
 
 Copied: stable/9/tools/regression/lib/libc/stdio/test-fopen.t (from r255303, head/tools/regression/lib/libc/stdio/test-fopen.t)
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ stable/9/tools/regression/lib/libc/stdio/test-fopen.t	Sun Oct 27 21:49:52 2013	(r257229, copy of r255303, head/tools/regression/lib/libc/stdio/test-fopen.t)
 @@ -0,0 +1,10 @@
 +#!/bin/sh
 +# $FreeBSD$
 +
 +cd `dirname $0`
 +
 +executable=`basename $0 .t`
 +
 +make $executable 2>&1 > /dev/null
 +
 +exec ./$executable
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jilles 
State-Changed-When: Sun Nov 3 19:35:34 UTC 2013 
State-Changed-Why:  
This is now implemented in stable/9, stable/10 and head. 
No MFC to older versions is planned. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=169320 
>Unformatted:
