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*68922Sbostic static char sccsid[] = "@(#)popen.c 8.2 (Berkeley) 04/27/95"; 1335451Sbostic #endif /* LIBC_SCCS and not lint */ 1422101Smckusick 1535458Sbostic #include <sys/param.h> 1635458Sbostic #include <sys/wait.h> 1753162Sbostic 1853162Sbostic #include <signal.h> 1940829Sbostic #include <errno.h> 2053162Sbostic #include <unistd.h> 212024Swnj #include <stdio.h> 2246597Sdonn #include <stdlib.h> 2346597Sdonn #include <string.h> 2439261Sbostic #include <paths.h> 2516676Ssam 2653162Sbostic static struct pid { 2753162Sbostic struct pid *next; 2853162Sbostic FILE *fp; 2953162Sbostic pid_t pid; 3053162Sbostic } *pidlist; 3153162Sbostic 322024Swnj FILE * 33*68922Sbostic popen(command, type) 34*68922Sbostic const char *command, *type; 352024Swnj { 3653162Sbostic struct pid *cur; 3735458Sbostic FILE *iop; 3853162Sbostic int pdes[2], pid; 392024Swnj 40*68922Sbostic if (*type != 'r' && *type != 'w' || type[1]) { 41*68922Sbostic errno = EINVAL; 4240870Skarels return (NULL); 43*68922Sbostic } 4435458Sbostic 4553162Sbostic if ((cur = malloc(sizeof(struct pid))) == NULL) 4653162Sbostic return (NULL); 4753162Sbostic 4853162Sbostic if (pipe(pdes) < 0) { 4953162Sbostic (void)free(cur); 5053162Sbostic return (NULL); 5135458Sbostic } 5253162Sbostic 5336302Skarels switch (pid = vfork()) { 5453162Sbostic case -1: /* Error. */ 5553162Sbostic (void)close(pdes[0]); 5653162Sbostic (void)close(pdes[1]); 5753162Sbostic (void)free(cur); 5840870Skarels return (NULL); 5935458Sbostic /* NOTREACHED */ 6053162Sbostic case 0: /* Child. */ 6135451Sbostic if (*type == 'r') { 6239651Sbostic if (pdes[1] != STDOUT_FILENO) { 6353162Sbostic (void)dup2(pdes[1], STDOUT_FILENO); 6453162Sbostic (void)close(pdes[1]); 6535458Sbostic } 6640870Skarels (void) close(pdes[0]); 6735458Sbostic } else { 6839651Sbostic if (pdes[0] != STDIN_FILENO) { 6953162Sbostic (void)dup2(pdes[0], STDIN_FILENO); 7053162Sbostic (void)close(pdes[0]); 7135458Sbostic } 7253162Sbostic (void)close(pdes[1]); 7314718Ssam } 74*68922Sbostic execl(_PATH_BSHELL, "sh", "-c", command, NULL); 7535458Sbostic _exit(127); 7635451Sbostic /* NOTREACHED */ 772024Swnj } 7853162Sbostic 7953162Sbostic /* Parent; assume fdopen can't fail. */ 8035458Sbostic if (*type == 'r') { 8135458Sbostic iop = fdopen(pdes[0], type); 8253162Sbostic (void)close(pdes[1]); 8335458Sbostic } else { 8435458Sbostic iop = fdopen(pdes[1], type); 8553162Sbostic (void)close(pdes[0]); 8615073Skarels } 8753162Sbostic 8853162Sbostic /* Link into list of file descriptors. */ 8953162Sbostic cur->fp = iop; 9053162Sbostic cur->pid = pid; 9153162Sbostic cur->next = pidlist; 9253162Sbostic pidlist = cur; 9353162Sbostic 9440870Skarels return (iop); 952024Swnj } 962024Swnj 9753162Sbostic /* 9853162Sbostic * pclose -- 9953162Sbostic * Pclose returns -1 if stream is not associated with a `popened' command, 10053162Sbostic * if already `pclosed', or waitpid returns an error. 10153162Sbostic */ 10246597Sdonn int 10335451Sbostic pclose(iop) 10435458Sbostic FILE *iop; 1052024Swnj { 10653162Sbostic register struct pid *cur, *last; 10736302Skarels int omask; 108*68922Sbostic int pstat; 10946597Sdonn pid_t pid; 1102024Swnj 11153162Sbostic /* Find the appropriate file pointer. */ 11253162Sbostic for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 11353162Sbostic if (cur->fp == iop) 11453162Sbostic break; 11553162Sbostic if (cur == NULL) 11640870Skarels return (-1); 11753162Sbostic 118*68922Sbostic (void)fclose(iop); 119*68922Sbostic 12040829Sbostic do { 121*68922Sbostic pid = waitpid(cur->pid, &pstat, 0); 12240829Sbostic } while (pid == -1 && errno == EINTR); 12353162Sbostic 12453162Sbostic /* Remove the entry from the linked list. */ 12553162Sbostic if (last == NULL) 12653162Sbostic pidlist = cur->next; 12753162Sbostic else 12853162Sbostic last->next = cur->next; 12953162Sbostic free(cur); 13053162Sbostic 131*68922Sbostic return (pid == -1 ? -1 : pstat); 1322024Swnj } 133