135675Sbostic /* 2*61427Sbostic * Copyright (c) 1988, 1993 3*61427Sbostic * The Regents of the University of California. 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*61427Sbostic static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 06/04/93"; 1435675Sbostic #endif /* not lint */ 1535675Sbostic 1635676Sbostic #include <sys/types.h> 1736304Skarels #include <sys/wait.h> 1854526Sandrew 1946669Sbostic #include <signal.h> 2046669Sbostic #include <unistd.h> 2135675Sbostic #include <stdio.h> 2246669Sbostic #include <stdlib.h> 2346669Sbostic #include <string.h> 2454526Sandrew #include "extern.h" 2535675Sbostic 2635676Sbostic /* 2735676Sbostic * Special version of popen which avoids call to shell. This insures noone 2835676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir 2935676Sbostic * command. 3035676Sbostic */ 3136304Skarels static int *pids; 3235675Sbostic static int fds; 3335675Sbostic 3435675Sbostic FILE * 3536276Sbostic ftpd_popen(program, type) 3635675Sbostic char *program, *type; 3735675Sbostic { 3835676Sbostic register char *cp; 3935675Sbostic FILE *iop; 4035676Sbostic int argc, gargc, pdes[2], pid; 4135676Sbostic char **pop, *argv[100], *gargv[1000], *vv[2]; 4235675Sbostic 4335675Sbostic if (*type != 'r' && *type != 'w' || type[1]) 4435675Sbostic return(NULL); 4535675Sbostic 4635675Sbostic if (!pids) { 4735675Sbostic if ((fds = getdtablesize()) <= 0) 4835675Sbostic return(NULL); 4936304Skarels if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 5035675Sbostic return(NULL); 5160086Sbostic memset(pids, 0, fds * sizeof(int)); 5235675Sbostic } 5335675Sbostic if (pipe(pdes) < 0) 5435675Sbostic return(NULL); 5535676Sbostic 5635676Sbostic /* break up string into pieces */ 5735676Sbostic for (argc = 0, cp = program;; cp = NULL) 5835676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n"))) 5935676Sbostic break; 6035676Sbostic 6135676Sbostic /* glob each piece */ 6235676Sbostic gargv[0] = argv[0]; 6335676Sbostic for (gargc = argc = 1; argv[argc]; argc++) { 6446669Sbostic if (!(pop = ftpglob(argv[argc]))) { /* globbing failed */ 6535676Sbostic vv[0] = argv[argc]; 6635676Sbostic vv[1] = NULL; 6735676Sbostic pop = copyblk(vv); 6835676Sbostic } 6935676Sbostic argv[argc] = (char *)pop; /* save to free later */ 7035676Sbostic while (*pop && gargc < 1000) 7135676Sbostic gargv[gargc++] = *pop++; 7235676Sbostic } 7335676Sbostic gargv[gargc] = NULL; 7435676Sbostic 7535676Sbostic iop = NULL; 7635675Sbostic switch(pid = vfork()) { 7735675Sbostic case -1: /* error */ 7835675Sbostic (void)close(pdes[0]); 7935675Sbostic (void)close(pdes[1]); 8036434Sbostic goto pfree; 8135675Sbostic /* NOTREACHED */ 8235675Sbostic case 0: /* child */ 8335675Sbostic if (*type == 'r') { 8435675Sbostic if (pdes[1] != 1) { 8535675Sbostic dup2(pdes[1], 1); 8636445Sbostic dup2(pdes[1], 2); /* stderr, too! */ 8735675Sbostic (void)close(pdes[1]); 8835675Sbostic } 8935675Sbostic (void)close(pdes[0]); 9035675Sbostic } else { 9135675Sbostic if (pdes[0] != 0) { 9235675Sbostic dup2(pdes[0], 0); 9335675Sbostic (void)close(pdes[0]); 9435675Sbostic } 9535675Sbostic (void)close(pdes[1]); 9635675Sbostic } 9735676Sbostic execv(gargv[0], gargv); 9835676Sbostic _exit(1); 9935675Sbostic } 10035675Sbostic /* parent; assume fdopen can't fail... */ 10135675Sbostic if (*type == 'r') { 10235675Sbostic iop = fdopen(pdes[0], type); 10335675Sbostic (void)close(pdes[1]); 10435675Sbostic } else { 10535675Sbostic iop = fdopen(pdes[1], type); 10635675Sbostic (void)close(pdes[0]); 10735675Sbostic } 10835675Sbostic pids[fileno(iop)] = pid; 10935676Sbostic 11036434Sbostic pfree: for (argc = 1; argv[argc] != NULL; argc++) { 11135676Sbostic blkfree((char **)argv[argc]); 11236434Sbostic free((char *)argv[argc]); 11336434Sbostic } 11435675Sbostic return(iop); 11535675Sbostic } 11635675Sbostic 11754526Sandrew int 11836304Skarels ftpd_pclose(iop) 11935675Sbostic FILE *iop; 12035675Sbostic { 12135675Sbostic register int fdes; 12236304Skarels int omask; 12336304Skarels union wait stat_loc; 12436304Skarels int pid; 12535675Sbostic 12635675Sbostic /* 12735675Sbostic * pclose returns -1 if stream is not associated with a 12835675Sbostic * `popened' command, or, if already `pclosed'. 12935675Sbostic */ 13036304Skarels if (pids == 0 || pids[fdes = fileno(iop)] == 0) 13135675Sbostic return(-1); 13235675Sbostic (void)fclose(iop); 13335675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 13446669Sbostic while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1); 13535675Sbostic (void)sigsetmask(omask); 13635675Sbostic pids[fdes] = 0; 13736304Skarels return(pid == -1 ? -1 : stat_loc.w_status); 13835675Sbostic } 139