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 * 842667Sbostic * %sccs.include.redist.c% 935675Sbostic * 1035675Sbostic */ 1135675Sbostic 1235675Sbostic #ifndef lint 13*46669Sbostic static char sccsid[] = "@(#)popen.c 5.9 (Berkeley) 02/25/91"; 1435675Sbostic #endif /* not lint */ 1535675Sbostic 1635676Sbostic #include <sys/types.h> 1736304Skarels #include <sys/wait.h> 18*46669Sbostic #include <signal.h> 19*46669Sbostic #include <unistd.h> 2035675Sbostic #include <stdio.h> 21*46669Sbostic #include <stdlib.h> 22*46669Sbostic #include <string.h> 2335675Sbostic 2435676Sbostic /* 2535676Sbostic * Special version of popen which avoids call to shell. This insures noone 2635676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir 2735676Sbostic * command. 2835676Sbostic */ 2936304Skarels static int *pids; 3035675Sbostic static int fds; 3135675Sbostic 3235675Sbostic FILE * 3336276Sbostic ftpd_popen(program, type) 3435675Sbostic char *program, *type; 3535675Sbostic { 3635676Sbostic register char *cp; 3735675Sbostic FILE *iop; 3835676Sbostic int argc, gargc, pdes[2], pid; 3935676Sbostic char **pop, *argv[100], *gargv[1000], *vv[2]; 40*46669Sbostic extern char **ftpglob(), **copyblk(); 4135675Sbostic 4235675Sbostic if (*type != 'r' && *type != 'w' || type[1]) 4335675Sbostic return(NULL); 4435675Sbostic 4535675Sbostic if (!pids) { 4635675Sbostic if ((fds = getdtablesize()) <= 0) 4735675Sbostic return(NULL); 4836304Skarels if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 4935675Sbostic return(NULL); 5036304Skarels bzero((char *)pids, fds * sizeof(int)); 5135675Sbostic } 5235675Sbostic if (pipe(pdes) < 0) 5335675Sbostic return(NULL); 5435676Sbostic 5535676Sbostic /* break up string into pieces */ 5635676Sbostic for (argc = 0, cp = program;; cp = NULL) 5735676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n"))) 5835676Sbostic break; 5935676Sbostic 6035676Sbostic /* glob each piece */ 6135676Sbostic gargv[0] = argv[0]; 6235676Sbostic for (gargc = argc = 1; argv[argc]; argc++) { 63*46669Sbostic if (!(pop = ftpglob(argv[argc]))) { /* globbing failed */ 6435676Sbostic vv[0] = argv[argc]; 6535676Sbostic vv[1] = NULL; 6635676Sbostic pop = copyblk(vv); 6735676Sbostic } 6835676Sbostic argv[argc] = (char *)pop; /* save to free later */ 6935676Sbostic while (*pop && gargc < 1000) 7035676Sbostic gargv[gargc++] = *pop++; 7135676Sbostic } 7235676Sbostic gargv[gargc] = NULL; 7335676Sbostic 7435676Sbostic iop = NULL; 7535675Sbostic switch(pid = vfork()) { 7635675Sbostic case -1: /* error */ 7735675Sbostic (void)close(pdes[0]); 7835675Sbostic (void)close(pdes[1]); 7936434Sbostic goto pfree; 8035675Sbostic /* NOTREACHED */ 8135675Sbostic case 0: /* child */ 8235675Sbostic if (*type == 'r') { 8335675Sbostic if (pdes[1] != 1) { 8435675Sbostic dup2(pdes[1], 1); 8536445Sbostic dup2(pdes[1], 2); /* stderr, too! */ 8635675Sbostic (void)close(pdes[1]); 8735675Sbostic } 8835675Sbostic (void)close(pdes[0]); 8935675Sbostic } else { 9035675Sbostic if (pdes[0] != 0) { 9135675Sbostic dup2(pdes[0], 0); 9235675Sbostic (void)close(pdes[0]); 9335675Sbostic } 9435675Sbostic (void)close(pdes[1]); 9535675Sbostic } 9635676Sbostic execv(gargv[0], gargv); 9735676Sbostic _exit(1); 9835675Sbostic } 9935675Sbostic /* parent; assume fdopen can't fail... */ 10035675Sbostic if (*type == 'r') { 10135675Sbostic iop = fdopen(pdes[0], type); 10235675Sbostic (void)close(pdes[1]); 10335675Sbostic } else { 10435675Sbostic iop = fdopen(pdes[1], type); 10535675Sbostic (void)close(pdes[0]); 10635675Sbostic } 10735675Sbostic pids[fileno(iop)] = pid; 10835676Sbostic 10936434Sbostic pfree: for (argc = 1; argv[argc] != NULL; argc++) { 11035676Sbostic blkfree((char **)argv[argc]); 11136434Sbostic free((char *)argv[argc]); 11236434Sbostic } 11335675Sbostic return(iop); 11435675Sbostic } 11535675Sbostic 11636304Skarels ftpd_pclose(iop) 11735675Sbostic FILE *iop; 11835675Sbostic { 11935675Sbostic register int fdes; 12036304Skarels int omask; 12136304Skarels union wait stat_loc; 12236304Skarels int pid; 12335675Sbostic 12435675Sbostic /* 12535675Sbostic * pclose returns -1 if stream is not associated with a 12635675Sbostic * `popened' command, or, if already `pclosed'. 12735675Sbostic */ 12836304Skarels if (pids == 0 || pids[fdes = fileno(iop)] == 0) 12935675Sbostic return(-1); 13035675Sbostic (void)fclose(iop); 13135675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 132*46669Sbostic while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1); 13335675Sbostic (void)sigsetmask(omask); 13435675Sbostic pids[fdes] = 0; 13536304Skarels return(pid == -1 ? -1 : stat_loc.w_status); 13635675Sbostic } 137