135675Sbostic /* 235675Sbostic * Copyright (c) 1988 The Regents of the University of California. 335675Sbostic * All rights reserved. 435675Sbostic * 535675Sbostic * This code is derived from software written by Ken Arnold and 635675Sbostic * published in UNIX Review, Vol. 6, No. 8. 735675Sbostic * 835675Sbostic * Redistribution and use in source and binary forms are permitted 935675Sbostic * provided that the above copyright notice and this paragraph are 1035675Sbostic * duplicated in all such forms and that any documentation, 1135675Sbostic * advertising materials, and other materials related to such 1235675Sbostic * distribution and use acknowledge that the software was developed 1335675Sbostic * by the University of California, Berkeley. The name of the 1435675Sbostic * University may not be used to endorse or promote products derived 1535675Sbostic * from this software without specific prior written permission. 1635675Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1735675Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1835675Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1935675Sbostic * 2035675Sbostic * static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 9/1/88"; 2135675Sbostic */ 2235675Sbostic 2335675Sbostic #ifndef lint 24*35676Sbostic static char sccsid[] = "@(#)popen.c 5.2 (Berkeley) 09/22/88"; 2535675Sbostic #endif /* not lint */ 2635675Sbostic 27*35676Sbostic #include <sys/types.h> 2835675Sbostic #include <sys/signal.h> 2935675Sbostic #include <stdio.h> 3035675Sbostic 31*35676Sbostic /* 32*35676Sbostic * Special version of popen which avoids call to shell. This insures noone 33*35676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir 34*35676Sbostic * command. 35*35676Sbostic */ 3635675Sbostic static uid_t *pids; 3735675Sbostic static int fds; 3835675Sbostic 3935675Sbostic FILE * 4035675Sbostic popen(program, type) 4135675Sbostic char *program, *type; 4235675Sbostic { 43*35676Sbostic register char *cp; 4435675Sbostic FILE *iop; 45*35676Sbostic int argc, gargc, pdes[2], pid; 46*35676Sbostic char **pop, *argv[100], *gargv[1000], *vv[2]; 47*35676Sbostic extern char **glob(), **copyblk(), *strtok(); 4835675Sbostic 4935675Sbostic if (*type != 'r' && *type != 'w' || type[1]) 5035675Sbostic return(NULL); 5135675Sbostic 5235675Sbostic if (!pids) { 5335675Sbostic if ((fds = getdtablesize()) <= 0) 5435675Sbostic return(NULL); 5535675Sbostic if (!(pids = 5635675Sbostic (uid_t *)malloc((u_int)(fds * sizeof(uid_t))))) 5735675Sbostic return(NULL); 5835675Sbostic bzero(pids, fds * sizeof(uid_t)); 5935675Sbostic } 6035675Sbostic if (pipe(pdes) < 0) 6135675Sbostic return(NULL); 62*35676Sbostic 63*35676Sbostic /* break up string into pieces */ 64*35676Sbostic for (argc = 0, cp = program;; cp = NULL) 65*35676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n"))) 66*35676Sbostic break; 67*35676Sbostic 68*35676Sbostic /* glob each piece */ 69*35676Sbostic gargv[0] = argv[0]; 70*35676Sbostic for (gargc = argc = 1; argv[argc]; argc++) { 71*35676Sbostic if (!(pop = glob(argv[argc]))) { /* globbing failed */ 72*35676Sbostic vv[0] = argv[argc]; 73*35676Sbostic vv[1] = NULL; 74*35676Sbostic pop = copyblk(vv); 75*35676Sbostic } 76*35676Sbostic argv[argc] = (char *)pop; /* save to free later */ 77*35676Sbostic while (*pop && gargc < 1000) 78*35676Sbostic gargv[gargc++] = *pop++; 79*35676Sbostic } 80*35676Sbostic gargv[gargc] = NULL; 81*35676Sbostic 82*35676Sbostic iop = NULL; 8335675Sbostic switch(pid = vfork()) { 8435675Sbostic case -1: /* error */ 8535675Sbostic (void)close(pdes[0]); 8635675Sbostic (void)close(pdes[1]); 87*35676Sbostic goto free; 8835675Sbostic /* NOTREACHED */ 8935675Sbostic case 0: /* child */ 9035675Sbostic if (*type == 'r') { 9135675Sbostic if (pdes[1] != 1) { 9235675Sbostic dup2(pdes[1], 1); 9335675Sbostic (void)close(pdes[1]); 9435675Sbostic } 9535675Sbostic (void)close(pdes[0]); 9635675Sbostic } else { 9735675Sbostic if (pdes[0] != 0) { 9835675Sbostic dup2(pdes[0], 0); 9935675Sbostic (void)close(pdes[0]); 10035675Sbostic } 10135675Sbostic (void)close(pdes[1]); 10235675Sbostic } 103*35676Sbostic execv(gargv[0], gargv); 104*35676Sbostic _exit(1); 10535675Sbostic } 10635675Sbostic /* parent; assume fdopen can't fail... */ 10735675Sbostic if (*type == 'r') { 10835675Sbostic iop = fdopen(pdes[0], type); 10935675Sbostic (void)close(pdes[1]); 11035675Sbostic } else { 11135675Sbostic iop = fdopen(pdes[1], type); 11235675Sbostic (void)close(pdes[0]); 11335675Sbostic } 11435675Sbostic pids[fileno(iop)] = pid; 115*35676Sbostic 116*35676Sbostic free: for (argc = 1; argv[argc] != NULL; argc++) 117*35676Sbostic blkfree((char **)argv[argc]); 11835675Sbostic return(iop); 11935675Sbostic } 12035675Sbostic 12135675Sbostic pclose(iop) 12235675Sbostic FILE *iop; 12335675Sbostic { 12435675Sbostic register int fdes; 12535675Sbostic long omask; 126*35676Sbostic int pid, stat_loc; 127*35676Sbostic u_int waitpid(); 12835675Sbostic 12935675Sbostic /* 13035675Sbostic * pclose returns -1 if stream is not associated with a 13135675Sbostic * `popened' command, or, if already `pclosed'. 13235675Sbostic */ 13335675Sbostic if (pids[fdes = fileno(iop)] == 0) 13435675Sbostic return(-1); 13535675Sbostic (void)fclose(iop); 13635675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 137*35676Sbostic while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1); 13835675Sbostic (void)sigsetmask(omask); 13935675Sbostic pids[fdes] = 0; 14035675Sbostic return(stat_loc); 14135675Sbostic } 142