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*36304Skarels static char sccsid[] = "@(#)popen.c 5.4 (Berkeley) 12/07/88"; 2535675Sbostic #endif /* not lint */ 2635675Sbostic 2735676Sbostic #include <sys/types.h> 2835675Sbostic #include <sys/signal.h> 29*36304Skarels #include <sys/wait.h> 3035675Sbostic #include <stdio.h> 3135675Sbostic 3235676Sbostic /* 3335676Sbostic * Special version of popen which avoids call to shell. This insures noone 3435676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir 3535676Sbostic * command. 3635676Sbostic */ 37*36304Skarels static int *pids; 3835675Sbostic static int fds; 3935675Sbostic 4035675Sbostic FILE * 4136276Sbostic ftpd_popen(program, type) 4235675Sbostic char *program, *type; 4335675Sbostic { 4435676Sbostic register char *cp; 4535675Sbostic FILE *iop; 4635676Sbostic int argc, gargc, pdes[2], pid; 4735676Sbostic char **pop, *argv[100], *gargv[1000], *vv[2]; 48*36304Skarels extern char **glob(), **copyblk(), *strtok(), *malloc(); 4935675Sbostic 5035675Sbostic if (*type != 'r' && *type != 'w' || type[1]) 5135675Sbostic return(NULL); 5235675Sbostic 5335675Sbostic if (!pids) { 5435675Sbostic if ((fds = getdtablesize()) <= 0) 5535675Sbostic return(NULL); 56*36304Skarels if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 5735675Sbostic return(NULL); 58*36304Skarels bzero((char *)pids, fds * sizeof(int)); 5935675Sbostic } 6035675Sbostic if (pipe(pdes) < 0) 6135675Sbostic return(NULL); 6235676Sbostic 6335676Sbostic /* break up string into pieces */ 6435676Sbostic for (argc = 0, cp = program;; cp = NULL) 6535676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n"))) 6635676Sbostic break; 6735676Sbostic 6835676Sbostic /* glob each piece */ 6935676Sbostic gargv[0] = argv[0]; 7035676Sbostic for (gargc = argc = 1; argv[argc]; argc++) { 7135676Sbostic if (!(pop = glob(argv[argc]))) { /* globbing failed */ 7235676Sbostic vv[0] = argv[argc]; 7335676Sbostic vv[1] = NULL; 7435676Sbostic pop = copyblk(vv); 7535676Sbostic } 7635676Sbostic argv[argc] = (char *)pop; /* save to free later */ 7735676Sbostic while (*pop && gargc < 1000) 7835676Sbostic gargv[gargc++] = *pop++; 7935676Sbostic } 8035676Sbostic gargv[gargc] = NULL; 8135676Sbostic 8235676Sbostic iop = NULL; 8335675Sbostic switch(pid = vfork()) { 8435675Sbostic case -1: /* error */ 8535675Sbostic (void)close(pdes[0]); 8635675Sbostic (void)close(pdes[1]); 8735676Sbostic 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 } 10335676Sbostic execv(gargv[0], gargv); 10435676Sbostic _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; 11535676Sbostic 11635676Sbostic free: for (argc = 1; argv[argc] != NULL; argc++) 11735676Sbostic blkfree((char **)argv[argc]); 11835675Sbostic return(iop); 11935675Sbostic } 12035675Sbostic 121*36304Skarels ftpd_pclose(iop) 12235675Sbostic FILE *iop; 12335675Sbostic { 12435675Sbostic register int fdes; 125*36304Skarels int omask; 126*36304Skarels union wait stat_loc; 127*36304Skarels int pid; 12835675Sbostic 12935675Sbostic /* 13035675Sbostic * pclose returns -1 if stream is not associated with a 13135675Sbostic * `popened' command, or, if already `pclosed'. 13235675Sbostic */ 133*36304Skarels if (pids == 0 || pids[fdes = fileno(iop)] == 0) 13435675Sbostic return(-1); 13535675Sbostic (void)fclose(iop); 13635675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 13735676Sbostic while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1); 13835675Sbostic (void)sigsetmask(omask); 13935675Sbostic pids[fdes] = 0; 140*36304Skarels return(pid == -1 ? -1 : stat_loc.w_status); 14135675Sbostic } 142