122101Smckusick /*
261111Sbostic * Copyright (c) 1988, 1993
361111Sbostic * The Regents of the University of California. All rights reserved.
435451Sbostic *
535458Sbostic * This code is derived from software written by Ken Arnold and
635458Sbostic * published in UNIX Review, Vol. 6, No. 8.
735451Sbostic *
842625Sbostic * %sccs.include.redist.c%
922101Smckusick */
1016676Ssam
1126575Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*69191Smckusick static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 05/03/95";
1335451Sbostic #endif /* LIBC_SCCS and not lint */
1422101Smckusick
1535458Sbostic #include <sys/param.h>
1635458Sbostic #include <sys/wait.h>
17*69191Smckusick #include <sys/socket.h>
1853162Sbostic
1953162Sbostic #include <signal.h>
2040829Sbostic #include <errno.h>
2153162Sbostic #include <unistd.h>
222024Swnj #include <stdio.h>
2346597Sdonn #include <stdlib.h>
2446597Sdonn #include <string.h>
2539261Sbostic #include <paths.h>
2616676Ssam
2753162Sbostic static struct pid {
2853162Sbostic struct pid *next;
2953162Sbostic FILE *fp;
3053162Sbostic pid_t pid;
3153162Sbostic } *pidlist;
3253162Sbostic
332024Swnj FILE *
popen(command,type)3468922Sbostic popen(command, type)
3568922Sbostic const char *command, *type;
362024Swnj {
3753162Sbostic struct pid *cur;
3835458Sbostic FILE *iop;
39*69191Smckusick int pdes[2], pid, twoway;
402024Swnj
41*69191Smckusick if (strchr(type, '+')) {
42*69191Smckusick twoway = 1;
43*69191Smckusick type = "r+";
44*69191Smckusick if (socketpair(AF_UNIX, SOCK_STREAM, 0, pdes) < 0)
45*69191Smckusick return (NULL);
46*69191Smckusick } else {
47*69191Smckusick twoway = 0;
48*69191Smckusick if (*type != 'r' && *type != 'w' || type[1] ||
49*69191Smckusick (pipe(pdes) < 0))
50*69191Smckusick return (NULL);
5168922Sbostic }
5235458Sbostic
5353162Sbostic if ((cur = malloc(sizeof(struct pid))) == NULL)
5453162Sbostic return (NULL);
5553162Sbostic
5636302Skarels switch (pid = vfork()) {
5753162Sbostic case -1: /* Error. */
5853162Sbostic (void)close(pdes[0]);
5953162Sbostic (void)close(pdes[1]);
6053162Sbostic (void)free(cur);
6140870Skarels return (NULL);
6235458Sbostic /* NOTREACHED */
6353162Sbostic case 0: /* Child. */
6435451Sbostic if (*type == 'r') {
6539651Sbostic if (pdes[1] != STDOUT_FILENO) {
6653162Sbostic (void)dup2(pdes[1], STDOUT_FILENO);
6753162Sbostic (void)close(pdes[1]);
68*69191Smckusick pdes[1] = STDOUT_FILENO;
6935458Sbostic }
7040870Skarels (void) close(pdes[0]);
71*69191Smckusick if (twoway && (pdes[1] != STDIN_FILENO))
72*69191Smckusick (void)dup2(pdes[1], STDIN_FILENO);
7335458Sbostic } else {
7439651Sbostic if (pdes[0] != STDIN_FILENO) {
7553162Sbostic (void)dup2(pdes[0], STDIN_FILENO);
7653162Sbostic (void)close(pdes[0]);
7735458Sbostic }
7853162Sbostic (void)close(pdes[1]);
7914718Ssam }
8068922Sbostic execl(_PATH_BSHELL, "sh", "-c", command, NULL);
8135458Sbostic _exit(127);
8235451Sbostic /* NOTREACHED */
832024Swnj }
8453162Sbostic
8553162Sbostic /* Parent; assume fdopen can't fail. */
8635458Sbostic if (*type == 'r') {
8735458Sbostic iop = fdopen(pdes[0], type);
8853162Sbostic (void)close(pdes[1]);
8935458Sbostic } else {
9035458Sbostic iop = fdopen(pdes[1], type);
9153162Sbostic (void)close(pdes[0]);
9215073Skarels }
9353162Sbostic
9453162Sbostic /* Link into list of file descriptors. */
9553162Sbostic cur->fp = iop;
9653162Sbostic cur->pid = pid;
9753162Sbostic cur->next = pidlist;
9853162Sbostic pidlist = cur;
9953162Sbostic
10040870Skarels return (iop);
1012024Swnj }
1022024Swnj
10353162Sbostic /*
10453162Sbostic * pclose --
10553162Sbostic * Pclose returns -1 if stream is not associated with a `popened' command,
10653162Sbostic * if already `pclosed', or waitpid returns an error.
10753162Sbostic */
10846597Sdonn int
pclose(iop)10935451Sbostic pclose(iop)
11035458Sbostic FILE *iop;
1112024Swnj {
11253162Sbostic register struct pid *cur, *last;
11336302Skarels int omask;
11468922Sbostic int pstat;
11546597Sdonn pid_t pid;
1162024Swnj
11753162Sbostic /* Find the appropriate file pointer. */
11853162Sbostic for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
11953162Sbostic if (cur->fp == iop)
12053162Sbostic break;
12153162Sbostic if (cur == NULL)
12240870Skarels return (-1);
12353162Sbostic
12468922Sbostic (void)fclose(iop);
12568922Sbostic
12640829Sbostic do {
12768922Sbostic pid = waitpid(cur->pid, &pstat, 0);
12840829Sbostic } while (pid == -1 && errno == EINTR);
12953162Sbostic
13053162Sbostic /* Remove the entry from the linked list. */
13153162Sbostic if (last == NULL)
13253162Sbostic pidlist = cur->next;
13353162Sbostic else
13453162Sbostic last->next = cur->next;
13553162Sbostic free(cur);
13653162Sbostic
13768922Sbostic return (pid == -1 ? -1 : pstat);
1382024Swnj }
139