Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libc/gen Factor out popen() code into separate functions...
details: https://anonhg.NetBSD.org/src/rev/dedf9bca02af
branches: trunk
changeset: 335673:dedf9bca02af
user: christos <christos%NetBSD.org@localhost>
date: Tue Jan 20 17:28:00 2015 +0000
description:
Factor out popen() code into separate functions and create popenve()
using the new functions, a safer version of popen() that does not
involve a shell. Correct manual page inaccuracies.
diffstat:
lib/libc/gen/Makefile.inc | 3 +-
lib/libc/gen/popen.3 | 40 ++++++--
lib/libc/gen/popen.c | 222 +++++++++++++++++++++++++++++++--------------
3 files changed, 184 insertions(+), 81 deletions(-)
diffs (truncated from 421 to 300 lines):
diff -r 4ec091088502 -r dedf9bca02af lib/libc/gen/Makefile.inc
--- a/lib/libc/gen/Makefile.inc Tue Jan 20 12:13:04 2015 +0000
+++ b/lib/libc/gen/Makefile.inc Tue Jan 20 17:28:00 2015 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.inc,v 1.190 2014/12/10 16:55:54 pooka Exp $
+# $NetBSD: Makefile.inc,v 1.191 2015/01/20 17:28:00 christos Exp $
# from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
# gen sources
@@ -147,6 +147,7 @@
MLINKS+=humanize_number.3 dehumanize_number.3
MLINKS+=makecontext.3 swapcontext.3
MLINKS+=popen.3 pclose.3
+MLINKS+=popen.3 popenve.3
MLINKS+=posix_spawn.3 posix_spawnp.3 \
posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addclose.3 \
posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_adddup2.3 \
diff -r 4ec091088502 -r dedf9bca02af lib/libc/gen/popen.3
--- a/lib/libc/gen/popen.3 Tue Jan 20 12:13:04 2015 +0000
+++ b/lib/libc/gen/popen.3 Tue Jan 20 17:28:00 2015 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: popen.3,v 1.18 2011/06/27 08:21:07 wiz Exp $
+.\" $NetBSD: popen.3,v 1.19 2015/01/20 17:28:00 christos Exp $
.\"
.\" Copyright (c) 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,11 +29,12 @@
.\"
.\" @(#)popen.3 8.2 (Berkeley) 5/3/95
.\"
-.Dd June 24, 2011
+.Dd January 19, 2015
.Dt POPEN 3
.Os
.Sh NAME
.Nm popen ,
+.Nm popenve ,
.Nm pclose
.Nd process
.Tn I/O
@@ -43,6 +44,8 @@
.In stdio.h
.Ft FILE *
.Fn popen "const char *command" "const char *type"
+.Ft FILE *
+.Fn popenve "const char *path" "char * const *argv" "char * const *envp" "const char *type"
.Ft int
.Fn pclose "FILE *stream"
.Sh DESCRIPTION
@@ -93,8 +96,20 @@
.Fl c
flag; interpretation, if any, is performed by the shell.
.Pp
+.Pp
+The
+.Fn popenve
+function is similar to
+.Fn popen
+but the first three arguments are passed
+to
+.Xr execve 2
+and there is no shell involved in the command invocation.
+.Pp
The return value from
.Fn popen
+and
+.Fn popenve
is a normal standard
.Tn I/O
stream in all respects
@@ -129,12 +144,13 @@
function returns
.Dv NULL
if the
-.Xr fork 2 ,
+.Xr vfork 2 ,
.Xr pipe 2 ,
or
.Xr socketpair 2
calls fail,
-or if it cannot allocate memory.
+or if it cannot allocate memory, preserving
+the errno from those functions.
.Pp
The
.Fn pclose
@@ -147,16 +163,15 @@
.Fa stream
has already been
.Dq pclosed ,
+setting errno to
+.Dv ESRCH
or if
.Xr wait4 2
-returns an error.
-.Sh ERRORS
-The
-.Fn popen
-function does not reliably set
-.Va errno .
+returns an error, preserving the errno returned by
+.Xr wait4 2.
.Sh SEE ALSO
.Xr sh 1 ,
+.Xr execve 2 ,
.Xr fork 2 ,
.Xr pipe 2 ,
.Xr socketpair 2 ,
@@ -206,3 +221,8 @@
.Xr sh 1 ,
never calls
.Xr csh 1 .
+.Pp
+The
+.Fn popenve
+function first appeared in
+.Nx 8 .
diff -r 4ec091088502 -r dedf9bca02af lib/libc/gen/popen.c
--- a/lib/libc/gen/popen.c Tue Jan 20 12:13:04 2015 +0000
+++ b/lib/libc/gen/popen.c Tue Jan 20 17:28:00 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: popen.c,v 1.32 2012/06/25 22:32:43 abs Exp $ */
+/* $NetBSD: popen.c,v 1.33 2015/01/20 17:28:00 christos Exp $ */
/*
* Copyright (c) 1988, 1993
@@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95";
#else
-__RCSID("$NetBSD: popen.c,v 1.32 2012/06/25 22:32:43 abs Exp $");
+__RCSID("$NetBSD: popen.c,v 1.33 2015/01/20 17:28:00 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@@ -77,95 +77,79 @@
static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
#endif
-FILE *
-popen(const char *command, const char *type)
+static struct pid *
+pdes_get(int *pdes, const char **type)
{
- struct pid *cur, *old;
- FILE *iop;
- const char * volatile xtype = type;
- int pdes[2], pid, serrno;
- volatile int twoway;
- int flags;
+ struct pid *cur;
+ int flags = strchr(*type, 'e') ? O_CLOEXEC : 0;
+ int serrno;
- _DIAGASSERT(command != NULL);
- _DIAGASSERT(xtype != NULL);
-
- flags = strchr(xtype, 'e') ? O_CLOEXEC : 0;
- if (strchr(xtype, '+')) {
+ if (strchr(*type, '+')) {
int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM;
- twoway = 1;
- xtype = "r+";
+ *type = "r+";
if (socketpair(AF_LOCAL, stype, 0, pdes) < 0)
return NULL;
} else {
- twoway = 0;
- xtype = strrchr(xtype, 'r') ? "r" : "w";
+ *type = strrchr(*type, 'r') ? "r" : "w";
if (pipe2(pdes, flags) == -1)
return NULL;
}
- if ((cur = malloc(sizeof(struct pid))) == NULL) {
- (void)close(pdes[0]);
- (void)close(pdes[1]);
- errno = ENOMEM;
- return (NULL);
- }
+ if ((cur = malloc(sizeof(*cur))) != NULL)
+ return cur;
+ serrno = errno;
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ errno = serrno;
+ return NULL;
+}
- (void)rwlock_rdlock(&pidlist_lock);
- (void)__readlockenv();
- switch (pid = vfork()) {
- case -1: /* Error. */
- serrno = errno;
- (void)__unlockenv();
- (void)rwlock_unlock(&pidlist_lock);
- free(cur);
- (void)close(pdes[0]);
- (void)close(pdes[1]);
- errno = serrno;
- return (NULL);
- /* NOTREACHED */
- case 0: /* Child. */
- /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
- from previous popen() calls that remain open in the
- parent process are closed in the new child process. */
- for (old = pidlist; old; old = old->next)
+static void
+pdes_child(int *pdes, const char *type)
+{
+ struct pid *old;
+
+ /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
+ from previous popen() calls that remain open in the
+ parent process are closed in the new child process. */
+ for (old = pidlist; old; old = old->next)
#ifdef _REENTRANT
- close(old->fd); /* don't allow a flush */
+ (void)close(old->fd); /* don't allow a flush */
#else
- close(fileno(old->fp)); /* don't allow a flush */
+ (void)close(fileno(old->fp)); /* don't allow a flush */
#endif
- if (*xtype == 'r') {
- (void)close(pdes[0]);
- if (pdes[1] != STDOUT_FILENO) {
- (void)dup2(pdes[1], STDOUT_FILENO);
- (void)close(pdes[1]);
- }
- if (twoway)
- (void)dup2(STDOUT_FILENO, STDIN_FILENO);
- } else {
+ if (type[0] == 'r') {
+ (void)close(pdes[0]);
+ if (pdes[1] != STDOUT_FILENO) {
+ (void)dup2(pdes[1], STDOUT_FILENO);
(void)close(pdes[1]);
- if (pdes[0] != STDIN_FILENO) {
- (void)dup2(pdes[0], STDIN_FILENO);
- (void)close(pdes[0]);
- }
}
+ if (type[1] == '+')
+ (void)dup2(STDOUT_FILENO, STDIN_FILENO);
+ } else {
+ (void)close(pdes[1]);
+ if (pdes[0] != STDIN_FILENO) {
+ (void)dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ }
+ }
+}
- execl(_PATH_BSHELL, "sh", "-c", command, NULL);
- _exit(127);
- /* NOTREACHED */
- }
- (void)__unlockenv();
+static void
+pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type)
+{
+ FILE *iop;
/* Parent; assume fdopen can't fail. */
- if (*xtype == 'r') {
- iop = fdopen(pdes[0], xtype);
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
#ifdef _REENTRANT
cur->fd = pdes[0];
#endif
(void)close(pdes[1]);
} else {
- iop = fdopen(pdes[1], xtype);
+ iop = fdopen(pdes[1], type);
#ifdef _REENTRANT
cur->fd = pdes[1];
#endif
@@ -177,9 +161,100 @@
cur->pid = pid;
cur->next = pidlist;
pidlist = cur;
- (void)rwlock_unlock(&pidlist_lock);
+}
+
+static void
+pdes_error(int *pdes, struct pid *cur)
+{
+ free(cur);
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+}
+
+FILE *
+popen(const char *cmd, const char *type)
+{
+ struct pid *cur;
+ int pdes[2], serrno;
+ pid_t pid;
Home |
Main Index |
Thread Index |
Old Index