summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/port/stdio/popen.c
diff options
context:
space:
mode:
authorMatthew Ahrens <matt@delphix.com>2011-10-18 12:21:34 -0700
committerMatthew Ahrens <matt@delphix.com>2011-10-18 12:21:34 -0700
commit462453d2d0c563559a4caf186db76954e563bd1a (patch)
tree7126716a3df77fcb2410e7b4020c94d918e7683f /usr/src/lib/libc/port/stdio/popen.c
parent9729663dccf3af95363464bd23939c153a918fd9 (diff)
downloadillumos-gate-462453d2d0c563559a4caf186db76954e563bd1a.tar.gz
1633 implement posix_spawn_pipe_np()
Reviewed by: Adam Leventhal <Adam.Leventhal@delphix.com> Reviewed by: Eric Schrock <Eric.Schrock@delphix.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Gordon Ross <gordon.w.ross@gmail.com> Approved by: Eric Schrock <Eric.Schrock@delphix.com>
Diffstat (limited to 'usr/src/lib/libc/port/stdio/popen.c')
-rw-r--r--usr/src/lib/libc/port/stdio/popen.c99
1 files changed, 42 insertions, 57 deletions
diff --git a/usr/src/lib/libc/port/stdio/popen.c b/usr/src/lib/libc/port/stdio/popen.c
index 2a86d36141..03365d04ef 100644
--- a/usr/src/lib/libc/port/stdio/popen.c
+++ b/usr/src/lib/libc/port/stdio/popen.c
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
@@ -50,13 +54,6 @@
#include "mse.h"
#include "libc.h"
-#define tst(a, b) (*mode == 'r'? (b) : (a))
-#define RDR 0
-#define WTR 1
-
-extern int __xpg4; /* defined in _xpg4.c; 0 if not xpg4-compiled program */
-extern const char **_environ;
-
static mutex_t popen_lock = DEFAULTMUTEX;
typedef struct node {
@@ -91,22 +88,15 @@ cleanup(void *arg)
FILE *
popen(const char *cmd, const char *mode)
{
- int p[2];
pid_t pid;
- int myside;
- int yourside;
- int fd;
+ int myfd, fd;
const char *shpath = _PATH_BSHELL;
FILE *iop;
- int stdio;
node_t *curr;
- char *argvec[4];
node_t *node;
- posix_spawnattr_t attr;
posix_spawn_file_actions_t fact;
+ posix_spawnattr_t attr;
int error;
- static const char *shell = "sh";
- static const char *sh_flg = "-c";
if ((node = lmalloc(sizeof (node_t))) == NULL)
return (NULL);
@@ -121,7 +111,19 @@ popen(const char *cmd, const char *mode)
errno = error;
return (NULL);
}
- if (pipe(p) < 0) {
+
+ if (access(shpath, X_OK)) /* XPG4 Requirement: */
+ shpath = ""; /* force child to fail immediately */
+
+
+ /*
+ * fdopen() can fail (if the fd is too high or we are out of memory),
+ * but we don't want to have any way to fail after creating the child
+ * process. So we fdopen() a dummy fd (myfd), and once we get the real
+ * fd from posix_spawn_pipe_np(), we dup2() the real fd onto the dummy.
+ */
+ myfd = open("/dev/null", O_RDWR);
+ if (myfd == -1) {
error = errno;
lfree(node, sizeof (node_t));
(void) posix_spawnattr_destroy(&attr);
@@ -129,23 +131,13 @@ popen(const char *cmd, const char *mode)
errno = error;
return (NULL);
}
-
- if (access(shpath, X_OK)) /* XPG4 Requirement: */
- shpath = ""; /* force child to fail immediately */
-
- myside = tst(p[WTR], p[RDR]);
- yourside = tst(p[RDR], p[WTR]);
- /* myside and yourside reverse roles in child */
- stdio = tst(0, 1);
-
- /* This will fail more quickly if we run out of fds */
- if ((iop = fdopen(myside, mode)) == NULL) {
+ iop = fdopen(myfd, mode);
+ if (iop == NULL) {
error = errno;
lfree(node, sizeof (node_t));
(void) posix_spawnattr_destroy(&attr);
(void) posix_spawn_file_actions_destroy(&fact);
- (void) close(yourside);
- (void) close(myside);
+ (void) close(myfd);
errno = error;
return (NULL);
}
@@ -155,64 +147,57 @@ popen(const char *cmd, const char *mode)
/* in the child, close all pipes from other popen's */
for (curr = head; curr != NULL && error == 0; curr = curr->next) {
/*
- * These conditions may apply if a previous iob returned
+ * The fd may no longer be open if an iob previously returned
* by popen() was closed with fclose() rather than pclose(),
- * or if close(fileno(iob)) was called. Don't let these
- * programming errors cause us to malfunction here.
+ * or if close(fileno(iob)) was called. Use fcntl() to check
+ * if the fd is still open, so that these programming errors
+ * won't cause us to malfunction here.
*/
- if ((fd = curr->fd) != myside && fd != yourside &&
- fcntl(fd, F_GETFD) >= 0)
- error = posix_spawn_file_actions_addclose(&fact, fd);
- }
- if (error == 0)
- error = posix_spawn_file_actions_addclose(&fact, myside);
- if (yourside != stdio) {
- if (error == 0)
- error = posix_spawn_file_actions_adddup2(&fact,
- yourside, stdio);
- if (error == 0)
+ if (fcntl(curr->fd, F_GETFD) >= 0) {
error = posix_spawn_file_actions_addclose(&fact,
- yourside);
+ curr->fd);
+ }
}
/*
* See the comments in port/stdio/system.c for why these
* non-portable posix_spawn() attributes are being used.
*/
- if (error == 0)
+ if (error == 0) {
error = posix_spawnattr_setflags(&attr,
POSIX_SPAWN_NOSIGCHLD_NP |
POSIX_SPAWN_WAITPID_NP |
POSIX_SPAWN_NOEXECERR_NP);
- if (error) {
+ }
+ if (error != 0) {
lmutex_unlock(&popen_lock);
lfree(node, sizeof (node_t));
(void) posix_spawnattr_destroy(&attr);
(void) posix_spawn_file_actions_destroy(&fact);
(void) fclose(iop);
- (void) close(yourside);
errno = error;
return (NULL);
}
- argvec[0] = (char *)shell;
- argvec[1] = (char *)sh_flg;
- argvec[2] = (char *)cmd;
- argvec[3] = NULL;
- error = posix_spawn(&pid, shpath, &fact, &attr,
- (char *const *)argvec, (char *const *)_environ);
+ error = posix_spawn_pipe_np(&pid, &fd, cmd, *mode != 'r', &fact, &attr);
(void) posix_spawnattr_destroy(&attr);
(void) posix_spawn_file_actions_destroy(&fact);
- (void) close(yourside);
- if (error) {
+ if (error != 0) {
lmutex_unlock(&popen_lock);
lfree(node, sizeof (node_t));
(void) fclose(iop);
errno = error;
return (NULL);
}
- _insert_nolock(pid, myside, node);
+ _insert_nolock(pid, myfd, node);
lmutex_unlock(&popen_lock);
+ /*
+ * myfd is the one that we fdopen()'ed; make it refer to the
+ * pipe to the child.
+ */
+ (void) dup2(fd, myfd);
+ (void) close(fd);
+
_SET_ORIENTATION_BYTE(iop);
return (iop);