135675Sbostic /* 2*66711Spendry * Copyright (c) 1988, 1993, 1994 361427Sbostic * 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*66711Spendry static char sccsid[] = "@(#)popen.c 8.2 (Berkeley) 04/04/94"; 1435675Sbostic #endif /* not lint */ 1535675Sbostic 1635676Sbostic #include <sys/types.h> 1736304Skarels #include <sys/wait.h> 1854526Sandrew 19*66711Spendry #include <errno.h> 20*66711Spendry #include <glob.h> 2146669Sbostic #include <signal.h> 2235675Sbostic #include <stdio.h> 2346669Sbostic #include <stdlib.h> 2446669Sbostic #include <string.h> 25*66711Spendry #include <unistd.h> 26*66711Spendry 2754526Sandrew #include "extern.h" 2835675Sbostic 2935676Sbostic /* 30*66711Spendry * Special version of popen which avoids call to shell. This ensures noone 3135676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir 3235676Sbostic * command. 3335676Sbostic */ 3436304Skarels static int *pids; 3535675Sbostic static int fds; 3635675Sbostic 3735675Sbostic FILE * 3836276Sbostic ftpd_popen(program, type) 3935675Sbostic char *program, *type; 4035675Sbostic { 41*66711Spendry char *cp; 4235675Sbostic FILE *iop; 4335676Sbostic int argc, gargc, pdes[2], pid; 44*66711Spendry char **pop, *argv[100], *gargv[1000]; 4535675Sbostic 4635675Sbostic if (*type != 'r' && *type != 'w' || type[1]) 47*66711Spendry return (NULL); 4835675Sbostic 4935675Sbostic if (!pids) { 5035675Sbostic if ((fds = getdtablesize()) <= 0) 51*66711Spendry return (NULL); 5236304Skarels if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 53*66711Spendry return (NULL); 5460086Sbostic memset(pids, 0, fds * sizeof(int)); 5535675Sbostic } 5635675Sbostic if (pipe(pdes) < 0) 57*66711Spendry return (NULL); 5835676Sbostic 5935676Sbostic /* break up string into pieces */ 6035676Sbostic for (argc = 0, cp = program;; cp = NULL) 6135676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n"))) 6235676Sbostic break; 6335676Sbostic 6435676Sbostic /* glob each piece */ 6535676Sbostic gargv[0] = argv[0]; 6635676Sbostic for (gargc = argc = 1; argv[argc]; argc++) { 67*66711Spendry glob_t gl; 68*66711Spendry int flags = GLOB_BRACE|GLOB_QUOTE|GLOB_TILDE; 69*66711Spendry 70*66711Spendry memset(&gl, 0, sizeof(gl)); 71*66711Spendry if (glob(argv[argc], flags, NULL, &gl)) 72*66711Spendry gargv[gargc++] = strdup(argv[argc]); 73*66711Spendry else 74*66711Spendry for (pop = gl.gl_pathv; *pop; pop++) 75*66711Spendry gargv[gargc++] = strdup(*pop); 76*66711Spendry globfree(&gl); 7735676Sbostic } 7835676Sbostic gargv[gargc] = NULL; 7935676Sbostic 8035676Sbostic iop = NULL; 8135675Sbostic switch(pid = vfork()) { 8235675Sbostic case -1: /* error */ 8335675Sbostic (void)close(pdes[0]); 8435675Sbostic (void)close(pdes[1]); 8536434Sbostic goto pfree; 8635675Sbostic /* NOTREACHED */ 8735675Sbostic case 0: /* child */ 8835675Sbostic if (*type == 'r') { 89*66711Spendry if (pdes[1] != STDOUT_FILENO) { 90*66711Spendry dup2(pdes[1], STDOUT_FILENO); 9135675Sbostic (void)close(pdes[1]); 9235675Sbostic } 93*66711Spendry dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */ 9435675Sbostic (void)close(pdes[0]); 9535675Sbostic } else { 96*66711Spendry if (pdes[0] != STDIN_FILENO) { 97*66711Spendry dup2(pdes[0], STDIN_FILENO); 9835675Sbostic (void)close(pdes[0]); 9935675Sbostic } 10035675Sbostic (void)close(pdes[1]); 10135675Sbostic } 10235676Sbostic execv(gargv[0], gargv); 10335676Sbostic _exit(1); 10435675Sbostic } 10535675Sbostic /* parent; assume fdopen can't fail... */ 10635675Sbostic if (*type == 'r') { 10735675Sbostic iop = fdopen(pdes[0], type); 10835675Sbostic (void)close(pdes[1]); 10935675Sbostic } else { 11035675Sbostic iop = fdopen(pdes[1], type); 11135675Sbostic (void)close(pdes[0]); 11235675Sbostic } 11335675Sbostic pids[fileno(iop)] = pid; 11435676Sbostic 115*66711Spendry pfree: for (argc = 1; gargv[argc] != NULL; argc++) 116*66711Spendry free(gargv[argc]); 117*66711Spendry 118*66711Spendry return (iop); 11935675Sbostic } 12035675Sbostic 12154526Sandrew int 12236304Skarels ftpd_pclose(iop) 12335675Sbostic FILE *iop; 12435675Sbostic { 125*66711Spendry int fdes, omask, status; 126*66711Spendry pid_t pid; 12735675Sbostic 12835675Sbostic /* 12935675Sbostic * pclose returns -1 if stream is not associated with a 13035675Sbostic * `popened' command, or, if already `pclosed'. 13135675Sbostic */ 13236304Skarels if (pids == 0 || pids[fdes = fileno(iop)] == 0) 133*66711Spendry return (-1); 13435675Sbostic (void)fclose(iop); 13535675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 136*66711Spendry while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) 137*66711Spendry continue; 13835675Sbostic (void)sigsetmask(omask); 13935675Sbostic pids[fdes] = 0; 140*66711Spendry if (pid < 0) 141*66711Spendry return (pid); 142*66711Spendry if (WIFEXITED(status)) 143*66711Spendry return (WEXITSTATUS(status)); 144*66711Spendry return (1); 14535675Sbostic } 146