globbing allocation/freeing wrong; bug report 4.3BSD/etc/149
[unix-history] / usr / src / libexec / ftpd / popen.c
CommitLineData
96c0abd0
KB
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 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 9/1/88";
21 */
22
23#ifndef lint
c075c3ce 24static char sccsid[] = "@(#)popen.c 5.5 (Berkeley) %G%";
96c0abd0
KB
25#endif /* not lint */
26
5f3a5fe7 27#include <sys/types.h>
96c0abd0 28#include <sys/signal.h>
882508af 29#include <sys/wait.h>
96c0abd0
KB
30#include <stdio.h>
31
5f3a5fe7
KB
32/*
33 * Special version of popen which avoids call to shell. This insures noone
34 * may create a pipe to a hidden program as a side effect of a list or dir
35 * command.
36 */
882508af 37static int *pids;
96c0abd0
KB
38static int fds;
39
40FILE *
5256bbac 41ftpd_popen(program, type)
96c0abd0
KB
42 char *program, *type;
43{
5f3a5fe7 44 register char *cp;
96c0abd0 45 FILE *iop;
5f3a5fe7
KB
46 int argc, gargc, pdes[2], pid;
47 char **pop, *argv[100], *gargv[1000], *vv[2];
882508af 48 extern char **glob(), **copyblk(), *strtok(), *malloc();
96c0abd0
KB
49
50 if (*type != 'r' && *type != 'w' || type[1])
51 return(NULL);
52
53 if (!pids) {
54 if ((fds = getdtablesize()) <= 0)
55 return(NULL);
882508af 56 if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
96c0abd0 57 return(NULL);
882508af 58 bzero((char *)pids, fds * sizeof(int));
96c0abd0
KB
59 }
60 if (pipe(pdes) < 0)
61 return(NULL);
5f3a5fe7
KB
62
63 /* break up string into pieces */
64 for (argc = 0, cp = program;; cp = NULL)
65 if (!(argv[argc++] = strtok(cp, " \t\n")))
66 break;
67
68 /* glob each piece */
69 gargv[0] = argv[0];
70 for (gargc = argc = 1; argv[argc]; argc++) {
71 if (!(pop = glob(argv[argc]))) { /* globbing failed */
72 vv[0] = argv[argc];
73 vv[1] = NULL;
74 pop = copyblk(vv);
75 }
76 argv[argc] = (char *)pop; /* save to free later */
77 while (*pop && gargc < 1000)
78 gargv[gargc++] = *pop++;
79 }
80 gargv[gargc] = NULL;
81
82 iop = NULL;
96c0abd0
KB
83 switch(pid = vfork()) {
84 case -1: /* error */
85 (void)close(pdes[0]);
86 (void)close(pdes[1]);
97f47643 87 goto pfree;
96c0abd0
KB
88 /* NOTREACHED */
89 case 0: /* child */
90 if (*type == 'r') {
91 if (pdes[1] != 1) {
92 dup2(pdes[1], 1);
93 (void)close(pdes[1]);
94 }
95 (void)close(pdes[0]);
96 } else {
97 if (pdes[0] != 0) {
98 dup2(pdes[0], 0);
99 (void)close(pdes[0]);
100 }
101 (void)close(pdes[1]);
102 }
5f3a5fe7
KB
103 execv(gargv[0], gargv);
104 _exit(1);
96c0abd0
KB
105 }
106 /* parent; assume fdopen can't fail... */
107 if (*type == 'r') {
108 iop = fdopen(pdes[0], type);
109 (void)close(pdes[1]);
110 } else {
111 iop = fdopen(pdes[1], type);
112 (void)close(pdes[0]);
113 }
114 pids[fileno(iop)] = pid;
5f3a5fe7 115
97f47643 116pfree: for (argc = 1; argv[argc] != NULL; argc++) {
5f3a5fe7 117 blkfree((char **)argv[argc]);
97f47643
KB
118 free((char *)argv[argc]);
119 }
96c0abd0
KB
120 return(iop);
121}
122
882508af 123ftpd_pclose(iop)
96c0abd0
KB
124 FILE *iop;
125{
126 register int fdes;
882508af
MK
127 int omask;
128 union wait stat_loc;
129 int pid;
96c0abd0
KB
130
131 /*
132 * pclose returns -1 if stream is not associated with a
133 * `popened' command, or, if already `pclosed'.
134 */
882508af 135 if (pids == 0 || pids[fdes = fileno(iop)] == 0)
96c0abd0
KB
136 return(-1);
137 (void)fclose(iop);
138 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
5f3a5fe7 139 while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
96c0abd0
KB
140 (void)sigsetmask(omask);
141 pids[fdes] = 0;
882508af 142 return(pid == -1 ? -1 : stat_loc.w_status);
96c0abd0 143}