122101Smckusick /* 2*61111Sbostic * Copyright (c) 1988, 1993 3*61111Sbostic * 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*61111Sbostic static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 06/04/93"; 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 * 3335451Sbostic popen(program, type) 3446597Sdonn const char *program; 3546597Sdonn const char *type; 362024Swnj { 3753162Sbostic struct pid *cur; 3835458Sbostic FILE *iop; 3953162Sbostic int pdes[2], pid; 402024Swnj 4135458Sbostic if (*type != 'r' && *type != 'w' || type[1]) 4240870Skarels return (NULL); 4335458Sbostic 4453162Sbostic if ((cur = malloc(sizeof(struct pid))) == NULL) 4553162Sbostic return (NULL); 4653162Sbostic 4753162Sbostic if (pipe(pdes) < 0) { 4853162Sbostic (void)free(cur); 4953162Sbostic return (NULL); 5035458Sbostic } 5153162Sbostic 5236302Skarels switch (pid = vfork()) { 5353162Sbostic case -1: /* Error. */ 5453162Sbostic (void)close(pdes[0]); 5553162Sbostic (void)close(pdes[1]); 5653162Sbostic (void)free(cur); 5740870Skarels return (NULL); 5835458Sbostic /* NOTREACHED */ 5953162Sbostic case 0: /* Child. */ 6035451Sbostic if (*type == 'r') { 6139651Sbostic if (pdes[1] != STDOUT_FILENO) { 6253162Sbostic (void)dup2(pdes[1], STDOUT_FILENO); 6353162Sbostic (void)close(pdes[1]); 6435458Sbostic } 6540870Skarels (void) close(pdes[0]); 6635458Sbostic } else { 6739651Sbostic if (pdes[0] != STDIN_FILENO) { 6853162Sbostic (void)dup2(pdes[0], STDIN_FILENO); 6953162Sbostic (void)close(pdes[0]); 7035458Sbostic } 7153162Sbostic (void)close(pdes[1]); 7214718Ssam } 7339261Sbostic execl(_PATH_BSHELL, "sh", "-c", program, NULL); 7435458Sbostic _exit(127); 7535451Sbostic /* NOTREACHED */ 762024Swnj } 7753162Sbostic 7853162Sbostic /* Parent; assume fdopen can't fail. */ 7935458Sbostic if (*type == 'r') { 8035458Sbostic iop = fdopen(pdes[0], type); 8153162Sbostic (void)close(pdes[1]); 8235458Sbostic } else { 8335458Sbostic iop = fdopen(pdes[1], type); 8453162Sbostic (void)close(pdes[0]); 8515073Skarels } 8653162Sbostic 8753162Sbostic /* Link into list of file descriptors. */ 8853162Sbostic cur->fp = iop; 8953162Sbostic cur->pid = pid; 9053162Sbostic cur->next = pidlist; 9153162Sbostic pidlist = cur; 9253162Sbostic 9340870Skarels return (iop); 942024Swnj } 952024Swnj 9653162Sbostic /* 9753162Sbostic * pclose -- 9853162Sbostic * Pclose returns -1 if stream is not associated with a `popened' command, 9953162Sbostic * if already `pclosed', or waitpid returns an error. 10053162Sbostic */ 10146597Sdonn int 10235451Sbostic pclose(iop) 10335458Sbostic FILE *iop; 1042024Swnj { 10553162Sbostic register struct pid *cur, *last; 10636302Skarels int omask; 10736309Sbostic union wait pstat; 10846597Sdonn pid_t pid; 1092024Swnj 11053162Sbostic (void)fclose(iop); 11153162Sbostic 11253162Sbostic /* Find the appropriate file pointer. */ 11353162Sbostic for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 11453162Sbostic if (cur->fp == iop) 11553162Sbostic break; 11653162Sbostic if (cur == NULL) 11740870Skarels return (-1); 11853162Sbostic 11953162Sbostic /* Get the status of the process. */ 12035458Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 12140829Sbostic do { 12253162Sbostic pid = waitpid(cur->pid, (int *) &pstat, 0); 12340829Sbostic } while (pid == -1 && errno == EINTR); 12453162Sbostic (void)sigsetmask(omask); 12553162Sbostic 12653162Sbostic /* Remove the entry from the linked list. */ 12753162Sbostic if (last == NULL) 12853162Sbostic pidlist = cur->next; 12953162Sbostic else 13053162Sbostic last->next = cur->next; 13153162Sbostic free(cur); 13253162Sbostic 13340870Skarels return (pid == -1 ? -1 : pstat.w_status); 1342024Swnj } 135