[BACK]Return to popen.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Annotation of src/lib/libc/gen/popen.c, Revision 1.29

1.29    ! christos    1: /*     $NetBSD: popen.c,v 1.28 2003/09/15 22:30:38 cl Exp $    */
1.10      cgd         2:
1.1       cgd         3: /*
1.7       jtc         4:  * Copyright (c) 1988, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software written by Ken Arnold and
                      8:  * published in UNIX Review, Vol. 6, No. 8.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
1.27      agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
                     34:
1.13      christos   35: #include <sys/cdefs.h>
1.1       cgd        36: #if defined(LIBC_SCCS) && !defined(lint)
1.10      cgd        37: #if 0
1.16      perry      38: static char sccsid[] = "@(#)popen.c    8.3 (Berkeley) 5/3/95";
1.10      cgd        39: #else
1.29    ! christos   40: __RCSID("$NetBSD: popen.c,v 1.28 2003/09/15 22:30:38 cl Exp $");
1.10      cgd        41: #endif
1.1       cgd        42: #endif /* LIBC_SCCS and not lint */
                     43:
1.14      jtc        44: #include "namespace.h"
1.1       cgd        45: #include <sys/param.h>
                     46: #include <sys/wait.h>
1.16      perry      47: #include <sys/socket.h>
1.7       jtc        48:
1.23      lukem      49: #include <assert.h>
                     50: #include <errno.h>
                     51: #include <paths.h>
1.7       jtc        52: #include <signal.h>
1.1       cgd        53: #include <stdio.h>
                     54: #include <stdlib.h>
                     55: #include <string.h>
1.23      lukem      56: #include <unistd.h>
1.26      nathanw    57: #include "reentrant.h"
1.14      jtc        58:
                     59: #ifdef __weak_alias
1.25      mycroft    60: __weak_alias(popen,_popen)
                     61: __weak_alias(pclose,_pclose)
1.14      jtc        62: #endif
1.1       cgd        63:
1.26      nathanw    64: #ifdef _REENTRANT
                     65: extern rwlock_t __environ_lock;
                     66: #endif
                     67:
1.7       jtc        68: static struct pid {
                     69:        struct pid *next;
                     70:        FILE *fp;
1.28      cl         71: #ifdef _REENTRANT
                     72:        int fd;
                     73: #endif
1.7       jtc        74:        pid_t pid;
                     75: } *pidlist;
                     76:
1.28      cl         77: #ifdef _REENTRANT
                     78: static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
                     79: #endif
                     80:
1.1       cgd        81: FILE *
1.29    ! christos   82: popen(const char *command, const char *type)
1.1       cgd        83: {
1.15      thorpej    84:        struct pid *cur, *old;
1.1       cgd        85:        FILE *iop;
1.29    ! christos   86:        const char * volatile xtype = type;
        !            87:        int pdes[2], pid, serrno;
        !            88:        volatile int twoway;
1.23      lukem      89:
                     90:        _DIAGASSERT(command != NULL);
1.29    ! christos   91:        _DIAGASSERT(xtype != NULL);
1.18      perry      92:
1.29    ! christos   93:        if (strchr(xtype, '+')) {
1.16      perry      94:                twoway = 1;
                     95:                type = "r+";
1.22      lukem      96:                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pdes) < 0)
1.16      perry      97:                        return (NULL);
                     98:        } else  {
                     99:                twoway = 0;
1.29    ! christos  100:                if ((*xtype != 'r' && *xtype != 'w') || xtype[1] ||
1.16      perry     101:                    (pipe(pdes) < 0)) {
                    102:                        errno = EINVAL;
                    103:                        return (NULL);
                    104:                }
1.9       jtc       105:        }
1.1       cgd       106:
1.20      tron      107:        if ((cur = malloc(sizeof(struct pid))) == NULL) {
                    108:                (void)close(pdes[0]);
                    109:                (void)close(pdes[1]);
1.23      lukem     110:                errno = ENOMEM;
1.7       jtc       111:                return (NULL);
1.20      tron      112:        }
1.7       jtc       113:
1.28      cl        114:        rwlock_rdlock(&pidlist_lock);
1.26      nathanw   115:        rwlock_rdlock(&__environ_lock);
1.1       cgd       116:        switch (pid = vfork()) {
1.7       jtc       117:        case -1:                        /* Error. */
1.23      lukem     118:                serrno = errno;
1.26      nathanw   119:                rwlock_unlock(&__environ_lock);
1.28      cl        120:                rwlock_unlock(&pidlist_lock);
1.20      tron      121:                free(cur);
1.7       jtc       122:                (void)close(pdes[0]);
                    123:                (void)close(pdes[1]);
1.23      lukem     124:                errno = serrno;
1.1       cgd       125:                return (NULL);
                    126:                /* NOTREACHED */
1.7       jtc       127:        case 0:                         /* Child. */
1.21      tv        128:                /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
                    129:                   from previous popen() calls that remain open in the
                    130:                   parent process are closed in the new child process. */
                    131:                for (old = pidlist; old; old = old->next)
1.28      cl        132: #ifdef _REENTRANT
                    133:                        close(old->fd); /* don't allow a flush */
                    134: #else
1.21      tv        135:                        close(fileno(old->fp)); /* don't allow a flush */
1.28      cl        136: #endif
1.21      tv        137:
1.29    ! christos  138:                if (*xtype == 'r') {
1.21      tv        139:                        (void)close(pdes[0]);
1.1       cgd       140:                        if (pdes[1] != STDOUT_FILENO) {
1.7       jtc       141:                                (void)dup2(pdes[1], STDOUT_FILENO);
                    142:                                (void)close(pdes[1]);
1.1       cgd       143:                        }
1.20      tron      144:                        if (twoway)
                    145:                                (void)dup2(STDOUT_FILENO, STDIN_FILENO);
1.1       cgd       146:                } else {
1.21      tv        147:                        (void)close(pdes[1]);
1.1       cgd       148:                        if (pdes[0] != STDIN_FILENO) {
1.7       jtc       149:                                (void)dup2(pdes[0], STDIN_FILENO);
                    150:                                (void)close(pdes[0]);
1.1       cgd       151:                        }
                    152:                }
1.12      jtc       153:
1.17      perry     154:                execl(_PATH_BSHELL, "sh", "-c", command, NULL);
1.1       cgd       155:                _exit(127);
                    156:                /* NOTREACHED */
                    157:        }
1.26      nathanw   158:        rwlock_unlock(&__environ_lock);
1.7       jtc       159:
                    160:        /* Parent; assume fdopen can't fail. */
1.29    ! christos  161:        if (*xtype == 'r') {
        !           162:                iop = fdopen(pdes[0], xtype);
1.28      cl        163: #ifdef _REENTRANT
                    164:                cur->fd = pdes[0];
                    165: #endif
1.7       jtc       166:                (void)close(pdes[1]);
1.1       cgd       167:        } else {
1.29    ! christos  168:                iop = fdopen(pdes[1], xtype);
1.28      cl        169: #ifdef _REENTRANT
                    170:                cur->fd = pdes[1];
                    171: #endif
1.7       jtc       172:                (void)close(pdes[0]);
1.1       cgd       173:        }
1.7       jtc       174:
                    175:        /* Link into list of file descriptors. */
                    176:        cur->fp = iop;
                    177:        cur->pid =  pid;
                    178:        cur->next = pidlist;
                    179:        pidlist = cur;
1.28      cl        180:        rwlock_unlock(&pidlist_lock);
1.7       jtc       181:
1.1       cgd       182:        return (iop);
                    183: }
                    184:
1.7       jtc       185: /*
                    186:  * pclose --
                    187:  *     Pclose returns -1 if stream is not associated with a `popened' command,
                    188:  *     if already `pclosed', or waitpid returns an error.
                    189:  */
1.1       cgd       190: int
                    191: pclose(iop)
                    192:        FILE *iop;
                    193: {
1.19      perry     194:        struct pid *cur, *last;
1.9       jtc       195:        int pstat;
1.1       cgd       196:        pid_t pid;
1.23      lukem     197:
                    198:        _DIAGASSERT(iop != NULL);
1.1       cgd       199:
1.28      cl        200:        rwlock_wrlock(&pidlist_lock);
                    201:
1.7       jtc       202:        /* Find the appropriate file pointer. */
                    203:        for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
                    204:                if (cur->fp == iop)
                    205:                        break;
1.28      cl        206:        if (cur == NULL) {
                    207:                rwlock_unlock(&pidlist_lock);
1.1       cgd       208:                return (-1);
1.28      cl        209:        }
1.16      perry     210:
                    211:        (void)fclose(iop);
1.7       jtc       212:
                    213:        /* Remove the entry from the linked list. */
                    214:        if (last == NULL)
                    215:                pidlist = cur->next;
                    216:        else
                    217:                last->next = cur->next;
1.28      cl        218:
                    219:        rwlock_unlock(&pidlist_lock);
                    220:
                    221:        do {
                    222:                pid = waitpid(cur->pid, &pstat, 0);
                    223:        } while (pid == -1 && errno == EINTR);
                    224:
1.7       jtc       225:        free(cur);
1.28      cl        226:
1.9       jtc       227:        return (pid == -1 ? -1 : pstat);
1.1       cgd       228: }

CVSweb <webmaster@jp.NetBSD.org>