1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software written by Ken Arnold and 6 * published in UNIX Review, Vol. 6, No. 8. 7 * 8 * %sccs.include.redist.c% 9 * 10 */ 11 12 #ifndef lint 13 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 06/04/93"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 19 #include <signal.h> 20 #include <unistd.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include "extern.h" 25 26 /* 27 * Special version of popen which avoids call to shell. This insures noone 28 * may create a pipe to a hidden program as a side effect of a list or dir 29 * command. 30 */ 31 static int *pids; 32 static int fds; 33 34 FILE * 35 ftpd_popen(program, type) 36 char *program, *type; 37 { 38 register char *cp; 39 FILE *iop; 40 int argc, gargc, pdes[2], pid; 41 char **pop, *argv[100], *gargv[1000], *vv[2]; 42 43 if (*type != 'r' && *type != 'w' || type[1]) 44 return(NULL); 45 46 if (!pids) { 47 if ((fds = getdtablesize()) <= 0) 48 return(NULL); 49 if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) 50 return(NULL); 51 memset(pids, 0, fds * sizeof(int)); 52 } 53 if (pipe(pdes) < 0) 54 return(NULL); 55 56 /* break up string into pieces */ 57 for (argc = 0, cp = program;; cp = NULL) 58 if (!(argv[argc++] = strtok(cp, " \t\n"))) 59 break; 60 61 /* glob each piece */ 62 gargv[0] = argv[0]; 63 for (gargc = argc = 1; argv[argc]; argc++) { 64 if (!(pop = ftpglob(argv[argc]))) { /* globbing failed */ 65 vv[0] = argv[argc]; 66 vv[1] = NULL; 67 pop = copyblk(vv); 68 } 69 argv[argc] = (char *)pop; /* save to free later */ 70 while (*pop && gargc < 1000) 71 gargv[gargc++] = *pop++; 72 } 73 gargv[gargc] = NULL; 74 75 iop = NULL; 76 switch(pid = vfork()) { 77 case -1: /* error */ 78 (void)close(pdes[0]); 79 (void)close(pdes[1]); 80 goto pfree; 81 /* NOTREACHED */ 82 case 0: /* child */ 83 if (*type == 'r') { 84 if (pdes[1] != 1) { 85 dup2(pdes[1], 1); 86 dup2(pdes[1], 2); /* stderr, too! */ 87 (void)close(pdes[1]); 88 } 89 (void)close(pdes[0]); 90 } else { 91 if (pdes[0] != 0) { 92 dup2(pdes[0], 0); 93 (void)close(pdes[0]); 94 } 95 (void)close(pdes[1]); 96 } 97 execv(gargv[0], gargv); 98 _exit(1); 99 } 100 /* parent; assume fdopen can't fail... */ 101 if (*type == 'r') { 102 iop = fdopen(pdes[0], type); 103 (void)close(pdes[1]); 104 } else { 105 iop = fdopen(pdes[1], type); 106 (void)close(pdes[0]); 107 } 108 pids[fileno(iop)] = pid; 109 110 pfree: for (argc = 1; argv[argc] != NULL; argc++) { 111 blkfree((char **)argv[argc]); 112 free((char *)argv[argc]); 113 } 114 return(iop); 115 } 116 117 int 118 ftpd_pclose(iop) 119 FILE *iop; 120 { 121 register int fdes; 122 int omask; 123 union wait stat_loc; 124 int pid; 125 126 /* 127 * pclose returns -1 if stream is not associated with a 128 * `popened' command, or, if already `pclosed'. 129 */ 130 if (pids == 0 || pids[fdes = fileno(iop)] == 0) 131 return(-1); 132 (void)fclose(iop); 133 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 134 while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1); 135 (void)sigsetmask(omask); 136 pids[fdes] = 0; 137 return(pid == -1 ? -1 : stat_loc.w_status); 138 } 139