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 * 8*42667Sbostic * %sccs.include.redist.c% 935675Sbostic * 1035675Sbostic */ 1135675Sbostic 1235675Sbostic #ifndef lint 13*42667Sbostic static char sccsid[] = "@(#)popen.c 5.8 (Berkeley) 06/01/90"; 1435675Sbostic #endif /* not lint */ 1535675Sbostic 1635676Sbostic #include <sys/types.h> 1735675Sbostic #include <sys/signal.h> 1836304Skarels #include <sys/wait.h> 1935675Sbostic #include <stdio.h> 2035675Sbostic 2135676Sbostic /* 2235676Sbostic * Special version of popen which avoids call to shell. This insures noone 2335676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir 2435676Sbostic * command. 2535676Sbostic */ 2636304Skarels static int *pids; 2735675Sbostic static int fds; 2835675Sbostic 2935675Sbostic FILE * 3036276Sbostic ftpd_popen(program, type) 3135675Sbostic char *program, *type; 3235675Sbostic { 3335676Sbostic register char *cp; 3435675Sbostic FILE *iop; 3535676Sbostic int argc, gargc, pdes[2], pid; 3635676Sbostic char **pop, *argv[100], *gargv[1000], *vv[2]; 3736304Skarels extern char **glob(), **copyblk(), *strtok(), *malloc(); 3835675Sbostic 3935675Sbostic if (*type != 'r' && *type != 'w' || type[1]) 4035675Sbostic return(NULL); 4135675Sbostic 4235675Sbostic if (!pids) { 4335675Sbostic if ((fds = getdtablesize()) <= 0) 4435675Sbostic return(NULL); 4536304Skarels if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 4635675Sbostic return(NULL); 4736304Skarels bzero((char *)pids, fds * sizeof(int)); 4835675Sbostic } 4935675Sbostic if (pipe(pdes) < 0) 5035675Sbostic return(NULL); 5135676Sbostic 5235676Sbostic /* break up string into pieces */ 5335676Sbostic for (argc = 0, cp = program;; cp = NULL) 5435676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n"))) 5535676Sbostic break; 5635676Sbostic 5735676Sbostic /* glob each piece */ 5835676Sbostic gargv[0] = argv[0]; 5935676Sbostic for (gargc = argc = 1; argv[argc]; argc++) { 6035676Sbostic if (!(pop = glob(argv[argc]))) { /* globbing failed */ 6135676Sbostic vv[0] = argv[argc]; 6235676Sbostic vv[1] = NULL; 6335676Sbostic pop = copyblk(vv); 6435676Sbostic } 6535676Sbostic argv[argc] = (char *)pop; /* save to free later */ 6635676Sbostic while (*pop && gargc < 1000) 6735676Sbostic gargv[gargc++] = *pop++; 6835676Sbostic } 6935676Sbostic gargv[gargc] = NULL; 7035676Sbostic 7135676Sbostic iop = NULL; 7235675Sbostic switch(pid = vfork()) { 7335675Sbostic case -1: /* error */ 7435675Sbostic (void)close(pdes[0]); 7535675Sbostic (void)close(pdes[1]); 7636434Sbostic goto pfree; 7735675Sbostic /* NOTREACHED */ 7835675Sbostic case 0: /* child */ 7935675Sbostic if (*type == 'r') { 8035675Sbostic if (pdes[1] != 1) { 8135675Sbostic dup2(pdes[1], 1); 8236445Sbostic dup2(pdes[1], 2); /* stderr, too! */ 8335675Sbostic (void)close(pdes[1]); 8435675Sbostic } 8535675Sbostic (void)close(pdes[0]); 8635675Sbostic } else { 8735675Sbostic if (pdes[0] != 0) { 8835675Sbostic dup2(pdes[0], 0); 8935675Sbostic (void)close(pdes[0]); 9035675Sbostic } 9135675Sbostic (void)close(pdes[1]); 9235675Sbostic } 9335676Sbostic execv(gargv[0], gargv); 9435676Sbostic _exit(1); 9535675Sbostic } 9635675Sbostic /* parent; assume fdopen can't fail... */ 9735675Sbostic if (*type == 'r') { 9835675Sbostic iop = fdopen(pdes[0], type); 9935675Sbostic (void)close(pdes[1]); 10035675Sbostic } else { 10135675Sbostic iop = fdopen(pdes[1], type); 10235675Sbostic (void)close(pdes[0]); 10335675Sbostic } 10435675Sbostic pids[fileno(iop)] = pid; 10535676Sbostic 10636434Sbostic pfree: for (argc = 1; argv[argc] != NULL; argc++) { 10735676Sbostic blkfree((char **)argv[argc]); 10836434Sbostic free((char *)argv[argc]); 10936434Sbostic } 11035675Sbostic return(iop); 11135675Sbostic } 11235675Sbostic 11336304Skarels ftpd_pclose(iop) 11435675Sbostic FILE *iop; 11535675Sbostic { 11635675Sbostic register int fdes; 11736304Skarels int omask; 11836304Skarels union wait stat_loc; 11936304Skarels int pid; 12035675Sbostic 12135675Sbostic /* 12235675Sbostic * pclose returns -1 if stream is not associated with a 12335675Sbostic * `popened' command, or, if already `pclosed'. 12435675Sbostic */ 12536304Skarels if (pids == 0 || pids[fdes = fileno(iop)] == 0) 12635675Sbostic return(-1); 12735675Sbostic (void)fclose(iop); 12835675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 12935676Sbostic while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1); 13035675Sbostic (void)sigsetmask(omask); 13135675Sbostic pids[fdes] = 0; 13236304Skarels return(pid == -1 ? -1 : stat_loc.w_status); 13335675Sbostic } 134