diff options
Diffstat (limited to 'lib/libc/gen')
-rw-r--r-- | lib/libc/gen/popen.3 | 7 | ||||
-rw-r--r-- | lib/libc/gen/popen.c | 30 |
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)); |