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