[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.31.2.1

1.31.2.1! yamt        1: /*     $NetBSD: popen.c,v 1.31 2011/06/26 16:42:41 christos 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.31.2.1! yamt       40: __RCSID("$NetBSD: popen.c,v 1.31 2011/06/26 16:42:41 christos 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.31      christos   57: #include <fcntl.h>
1.30      tron       58:
                     59: #include "env.h"
1.26      nathanw    60: #include "reentrant.h"
1.14      jtc        61:
                     62: #ifdef __weak_alias
1.25      mycroft    63: __weak_alias(popen,_popen)
                     64: __weak_alias(pclose,_pclose)
1.14      jtc        65: #endif
1.1       cgd        66:
1.7       jtc        67: static struct pid {
                     68:        struct pid *next;
                     69:        FILE *fp;
1.28      cl         70: #ifdef _REENTRANT
                     71:        int fd;
                     72: #endif
1.7       jtc        73:        pid_t pid;
                     74: } *pidlist;
                     75:
1.28      cl         76: #ifdef _REENTRANT
                     77: static rwlock_t pidlist_lock = RWLOCK_INITIALIZER;
                     78: #endif
                     79:
1.1       cgd        80: FILE *
1.29      christos   81: popen(const char *command, const char *type)
1.1       cgd        82: {
1.15      thorpej    83:        struct pid *cur, *old;
1.1       cgd        84:        FILE *iop;
1.29      christos   85:        const char * volatile xtype = type;
                     86:        int pdes[2], pid, serrno;
                     87:        volatile int twoway;
1.31      christos   88:        int flags;
1.23      lukem      89:
                     90:        _DIAGASSERT(command != NULL);
1.29      christos   91:        _DIAGASSERT(xtype != NULL);
1.18      perry      92:
1.31      christos   93:        flags = strchr(xtype, 'e') ? O_CLOEXEC : 0;
1.29      christos   94:        if (strchr(xtype, '+')) {
1.31      christos   95:                int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM;
1.16      perry      96:                twoway = 1;
1.31      christos   97:                xtype = "r+";
                     98:                if (socketpair(AF_LOCAL, stype, 0, pdes) < 0)
                     99:                        return NULL;
1.16      perry     100:        } else  {
                    101:                twoway = 0;
1.31      christos  102:                xtype = strrchr(xtype, 'r') ? "r" : "w";
                    103:                if (pipe2(pdes, flags) == -1)
                    104:                        return NULL;
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.30      tron      114:        (void)rwlock_rdlock(&pidlist_lock);
                    115:        (void)__readlockenv();
1.1       cgd       116:        switch (pid = vfork()) {
1.7       jtc       117:        case -1:                        /* Error. */
1.23      lukem     118:                serrno = errno;
1.30      tron      119:                (void)__unlockenv();
                    120:                (void)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.30      tron      158:        (void)__unlockenv();
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.30      tron      180:        (void)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
1.31.2.1! yamt      191: pclose(FILE *iop)
1.1       cgd       192: {
1.19      perry     193:        struct pid *cur, *last;
1.9       jtc       194:        int pstat;
1.1       cgd       195:        pid_t pid;
1.23      lukem     196:
                    197:        _DIAGASSERT(iop != NULL);
1.1       cgd       198:
1.28      cl        199:        rwlock_wrlock(&pidlist_lock);
                    200:
1.7       jtc       201:        /* Find the appropriate file pointer. */
                    202:        for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
                    203:                if (cur->fp == iop)
                    204:                        break;
1.28      cl        205:        if (cur == NULL) {
1.30      tron      206:                (void)rwlock_unlock(&pidlist_lock);
1.1       cgd       207:                return (-1);
1.28      cl        208:        }
1.16      perry     209:
                    210:        (void)fclose(iop);
1.7       jtc       211:
                    212:        /* Remove the entry from the linked list. */
                    213:        if (last == NULL)
                    214:                pidlist = cur->next;
                    215:        else
                    216:                last->next = cur->next;
1.28      cl        217:
1.30      tron      218:        (void)rwlock_unlock(&pidlist_lock);
1.28      cl        219:
                    220:        do {
                    221:                pid = waitpid(cur->pid, &pstat, 0);
                    222:        } while (pid == -1 && errno == EINTR);
                    223:
1.7       jtc       224:        free(cur);
1.28      cl        225:
1.9       jtc       226:        return (pid == -1 ? -1 : pstat);
1.1       cgd       227: }

CVSweb <webmaster@jp.NetBSD.org>