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