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