From owner-svn-src-head@FreeBSD.ORG Mon May 20 17:31:19 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 647FF455; Mon, 20 May 2013 17:31:19 +0000 (UTC) (envelope-from jilles@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 5675386B; Mon, 20 May 2013 17:31:19 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r4KHVJgc074034; Mon, 20 May 2013 17:31:19 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r4KHVIpT074031; Mon, 20 May 2013 17:31:18 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201305201731.r4KHVIpT074031@svn.freebsd.org> From: Jilles Tjoelker Date: Mon, 20 May 2013 17:31:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r250827 - in head: lib/libc/gen tools/regression/lib/libc/gen X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 May 2013 17:31:19 -0000 Author: jilles Date: Mon May 20 17:31:18 2013 New Revision: 250827 URL: http://svnweb.freebsd.org/changeset/base/250827 Log: popen(): Add 'e' mode character to set close-on-exec on the new fd. If 'e' is used, the kernel must support the recently added pipe2() system call. The use of pipe2() with O_CLOEXEC also fixes race conditions between concurrent popen() calls from different threads, even if the close-on-exec flag on the fd of the returned FILE is later cleared (because popen() closes all file descriptors from earlier popen() calls in the child process). Therefore, this approach should be used in all cases when pipe2() can be assumed present. The old version of popen() rejects "re" and "we" but treats "r+e" like "r+". Modified: head/lib/libc/gen/popen.3 head/lib/libc/gen/popen.c head/tools/regression/lib/libc/gen/test-popen.c Modified: head/lib/libc/gen/popen.3 ============================================================================== --- head/lib/libc/gen/popen.3 Mon May 20 15:11:30 2013 (r250826) +++ head/lib/libc/gen/popen.3 Mon May 20 17:31:18 2013 (r250827) @@ -28,7 +28,7 @@ .\" @(#)popen.3 8.2 (Berkeley) 5/3/95 .\" $FreeBSD$ .\" -.Dd May 3, 1995 +.Dd May 20, 2013 .Dt POPEN 3 .Os .Sh NAME @@ -79,6 +79,11 @@ for writing, or .Ql r+ for reading and writing. .Pp +A letter +.Ql e +may be appended to that to request that the underlying file descriptor +be set close-on-exec. +.Pp The .Fa command argument is a pointer to a null-terminated string Modified: head/lib/libc/gen/popen.c ============================================================================== --- head/lib/libc/gen/popen.c Mon May 20 15:11:30 2013 (r250826) +++ head/lib/libc/gen/popen.c Mon May 20 17:31:18 2013 (r250827) @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -71,10 +72,11 @@ popen(command, type) { struct pid *cur; FILE *iop; - int pdes[2], pid, twoway; + int pdes[2], pid, twoway, cloexec; char *argv[4]; struct pid *p; + cloexec = strchr(type, 'e') != NULL; /* * Lite2 introduced two-way popen() pipes using _socketpair(). * FreeBSD's pipe() is bidirectional, so we use that. @@ -84,10 +86,11 @@ popen(command, type) type = "r+"; } else { twoway = 0; - if ((*type != 'r' && *type != 'w') || type[1]) + if ((*type != 'r' && *type != 'w') || + (type[1] && (type[1] != 'e' || type[2]))) return (NULL); } - if (pipe(pdes) < 0) + if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0) return (NULL); if ((cur = malloc(sizeof(struct pid))) == NULL) { @@ -120,20 +123,29 @@ popen(command, type) * the compiler is free to corrupt all the local * variables. */ - (void)_close(pdes[0]); + if (!cloexec) + (void)_close(pdes[0]); if (pdes[1] != STDOUT_FILENO) { (void)_dup2(pdes[1], STDOUT_FILENO); - (void)_close(pdes[1]); + if (!cloexec) + (void)_close(pdes[1]); if (twoway) (void)_dup2(STDOUT_FILENO, STDIN_FILENO); - } else if (twoway && (pdes[1] != STDIN_FILENO)) + } else if (twoway && (pdes[1] != STDIN_FILENO)) { (void)_dup2(pdes[1], STDIN_FILENO); + if (cloexec) + (void)_fcntl(pdes[1], F_SETFD, 0); + } else if (cloexec) + (void)_fcntl(pdes[1], F_SETFD, 0); } else { if (pdes[0] != STDIN_FILENO) { (void)_dup2(pdes[0], STDIN_FILENO); - (void)_close(pdes[0]); - } - (void)_close(pdes[1]); + if (!cloexec) + (void)_close(pdes[0]); + } else if (cloexec) + (void)_fcntl(pdes[0], F_SETFD, 0); + if (!cloexec) + (void)_close(pdes[1]); } SLIST_FOREACH(p, &pidlist, next) (void)_close(fileno(p->fp)); Modified: head/tools/regression/lib/libc/gen/test-popen.c ============================================================================== --- head/tools/regression/lib/libc/gen/test-popen.c Mon May 20 15:11:30 2013 (r250826) +++ head/tools/regression/lib/libc/gen/test-popen.c Mon May 20 17:31:18 2013 (r250827) @@ -70,10 +70,10 @@ main(int argc, char *argv[]) FILE *fp, *fp2; int i, j, status; const char *mode; - const char *allmodes[] = { "r", "w", "r+" }; - const char *rmodes[] = { "r", "r+" }; - const char *wmodes[] = { "w", "r+" }; - const char *rwmodes[] = { "r+" }; + const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" }; + const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" }; + const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" }; + const char *rwmodes[] = { "r+", "r+e", "re+" }; char buf[80]; struct sigaction act, oact;