summaryrefslogtreecommitdiffstats
path: root/lib/libc/gen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/gen')
-rw-r--r--lib/libc/gen/popen.37
-rw-r--r--lib/libc/gen/popen.c30
2 files changed, 27 insertions, 10 deletions
diff --git a/lib/libc/gen/popen.3 b/lib/libc/gen/popen.3
index 90297e4..386a0bd 100644
--- a/lib/libc/gen/popen.3
+++ b/lib/libc/gen/popen.3
@@ -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
diff --git a/lib/libc/gen/popen.c b/lib/libc/gen/popen.c
index b123234..b0597c8 100644
--- a/lib/libc/gen/popen.c
+++ b/lib/libc/gen/popen.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <signal.h>
#include <errno.h>
+#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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));
OpenPOWER on IntegriCloud