Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* popen.c: A "safe" pipe open routine. |
2 | ||
3 | %%% portions-copyright-cmetz-96 | |
4 | Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights | |
5 | Reserved. The Inner Net License Version 2 applies to these portions of | |
6 | the software. | |
7 | You should have received a copy of the license with this software. If | |
8 | you didn't get a copy, you may request one from <license@inner.net>. | |
9 | ||
10 | Portions of this software are Copyright 1995 by Randall Atkinson and Dan | |
11 | McDonald, All Rights Reserved. All Rights under this copyright are assigned | |
12 | to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and | |
13 | License Agreement applies to this software. | |
14 | ||
15 | History: | |
16 | ||
17 | Modified by cmetz for OPIE 2.31. Merged in some 4.4BSD-Lite fixes. | |
18 | Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. | |
19 | Removed useless string. ifdef around some headers. | |
20 | Modified at NRL for OPIE 2.1. Optimized for only one pipe at a time. | |
21 | Added minimal version of sigprocmask(). Moved some pid_t | |
22 | dancing to the config headers. | |
23 | Modified at NRL for OPIE 2.0. | |
24 | Originally from BSD. | |
25 | ||
f5bc2dc2 | 26 | $FreeBSD: head/contrib/opie/popen.c 117501 2003-07-13 05:59:50Z kris $ |
984263bc MD |
27 | */ |
28 | /* | |
29 | * Copyright (c) 1988, 1993, 1994 | |
30 | * The Regents of the University of California. All rights reserved. | |
31 | * | |
32 | * This code is derived from software written by Ken Arnold and | |
33 | * published in UNIX Review, Vol. 6, No. 8. | |
34 | * | |
35 | * Redistribution and use in source and binary forms, with or without | |
36 | * modification, are permitted provided that the following conditions | |
37 | * are met: | |
38 | * 1. Redistributions of source code must retain the above copyright | |
39 | * notice, this list of conditions and the following disclaimer. | |
40 | * 2. Redistributions in binary form must reproduce the above copyright | |
41 | * notice, this list of conditions and the following disclaimer in the | |
42 | * documentation and/or other materials provided with the distribution. | |
43 | * 3. All advertising materials mentioning features or use of this software | |
44 | * must display the following acknowledgement: | |
45 | * This product includes software developed by the University of | |
46 | * California, Berkeley and its contributors. | |
47 | * 4. Neither the name of the University nor the names of its contributors | |
48 | * may be used to endorse or promote products derived from this software | |
49 | * without specific prior written permission. | |
50 | * | |
51 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
54 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
55 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
56 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
57 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
58 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
59 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
60 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
61 | * SUCH DAMAGE. | |
62 | * | |
63 | */ | |
64 | ||
65 | #include "opie_cfg.h" | |
66 | ||
67 | #include <sys/types.h> | |
68 | #include <sys/wait.h> | |
69 | #if HAVE_SIGNAL_H | |
70 | #include <signal.h> | |
71 | #endif /* HAVE_SIGNAL_H */ | |
72 | #if HAVE_SYS_SIGNAL_H | |
73 | #include <sys/signal.h> | |
74 | #endif /* HAVE_SYS_SIGNAL_H */ | |
75 | #if HAVE_UNISTD_H | |
76 | #include <unistd.h> | |
77 | #endif /* HAVE_UNISTD_H */ | |
78 | #include <stdio.h> | |
79 | #if HAVE_STDLIB_H | |
80 | #include <stdlib.h> | |
81 | #endif /* HAVE_STDLIB_H */ | |
82 | #if HAVE_STRING_H | |
83 | #include <string.h> | |
84 | #endif /* HAVE_STRING_H */ | |
85 | ||
86 | #include "opie.h" | |
87 | ||
f5bc2dc2 SW |
88 | #define MAXUSRARGS 100 |
89 | #define MAXGLOBARGS 1000 | |
90 | ||
984263bc MD |
91 | char **ftpglob __P((register char *)); |
92 | char **copyblk __P((char **)); | |
93 | VOIDRET blkfree __P((char **)); | |
94 | ||
95 | /* | |
96 | * Special version of popen which avoids call to shell. This ensures noone | |
97 | * may create a pipe to a hidden program as a side effect of a list or dir | |
98 | * command. | |
99 | */ | |
100 | static pid_t child_pid = -1; | |
101 | static int pipe_fd; | |
102 | ||
103 | extern char **environ; | |
104 | ||
105 | FILE *ftpd_popen FUNCTION((program, type), char *program AND char *type) | |
106 | { | |
107 | char *cp; | |
108 | FILE *iop; | |
109 | int argc, gargc, pdes[2]; | |
f5bc2dc2 | 110 | char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS], *vv[2]; |
984263bc MD |
111 | |
112 | if ((*type != 'r' && *type != 'w') || type[1]) | |
113 | return (NULL); | |
114 | ||
115 | if (pipe(pdes) < 0) | |
116 | return (NULL); | |
117 | ||
118 | /* break up string into pieces */ | |
f5bc2dc2 | 119 | for (argc = 0, cp = program; argc < MAXUSRARGS-1; cp = NULL) { |
984263bc MD |
120 | if (!(argv[argc++] = strtok(cp, " \t\n"))) |
121 | break; | |
f5bc2dc2 SW |
122 | } |
123 | argv[argc - 1] = NULL; | |
984263bc MD |
124 | |
125 | /* glob each piece */ | |
126 | gargv[0] = argv[0]; | |
f5bc2dc2 | 127 | for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) { |
984263bc MD |
128 | if (!(pop = (char **) ftpglob(argv[argc]))) { |
129 | /* globbing failed */ | |
130 | vv[0] = argv[argc]; | |
131 | vv[1] = NULL; | |
132 | pop = (char **) copyblk(vv); | |
133 | } | |
134 | argv[argc] = (char *) pop; /* save to free later */ | |
f5bc2dc2 | 135 | while (*pop && gargc < MAXGLOBARGS-1) |
984263bc MD |
136 | gargv[gargc++] = *pop++; |
137 | } | |
138 | gargv[gargc] = NULL; | |
139 | ||
140 | iop = NULL; | |
141 | switch (child_pid = fork()) { | |
142 | case -1: /* error */ | |
143 | close(pdes[0]); | |
144 | close(pdes[1]); | |
145 | goto pfree; | |
146 | /* NOTREACHED */ | |
147 | case 0: /* child */ | |
148 | if (*type == 'r') { | |
149 | if (pdes[1] != 1) { | |
150 | dup2(pdes[1], 1); | |
151 | dup2(pdes[1], 2); /* stderr, too! */ | |
152 | close(pdes[1]); | |
153 | } | |
154 | close(pdes[0]); | |
155 | } else { | |
156 | if (pdes[0] != 0) { | |
157 | dup2(pdes[0], 0); | |
158 | close(pdes[0]); | |
159 | } | |
160 | close(pdes[1]); | |
161 | } | |
162 | environ = NULL; | |
163 | execv(gargv[0], gargv); | |
164 | _exit(1); | |
165 | } | |
166 | ||
167 | /* parent; assume fdopen can't fail... */ | |
168 | if (*type == 'r') { | |
169 | iop = fdopen(pipe_fd = pdes[0], type); | |
170 | close(pdes[1]); | |
171 | } else { | |
172 | iop = fdopen(pipe_fd = pdes[1], type); | |
173 | close(pdes[0]); | |
174 | } | |
175 | ||
176 | pfree: for (argc = 1; argv[argc] != NULL; argc++) { | |
177 | blkfree((char **) argv[argc]); | |
178 | free((char *) argv[argc]); | |
179 | } | |
180 | return (iop); | |
181 | } | |
182 | ||
183 | int ftpd_pclose FUNCTION((iop), FILE *iop) | |
184 | { | |
185 | int status; | |
186 | pid_t pid; | |
187 | sigset_t omask, mask; | |
188 | ||
189 | sigemptyset(&mask); | |
190 | sigaddset(&mask, SIGINT); | |
191 | sigaddset(&mask, SIGQUIT); | |
192 | sigaddset(&mask, SIGHUP); | |
193 | ||
194 | /* pclose returns -1 if stream is not associated with a `popened' command, | |
195 | or, if already `pclosed'. */ | |
196 | if ((child_pid < 0) || (fileno(iop) != pipe_fd)) | |
197 | return (-1); | |
198 | ||
199 | fclose(iop); | |
200 | sigprocmask(SIG_BLOCK, &mask, &omask); | |
201 | ||
202 | while ((pid = wait(&status)) != child_pid && (pid != -1)); | |
203 | sigprocmask(SIG_SETMASK, &omask, NULL); | |
204 | ||
205 | child_pid = -1; | |
206 | pipe_fd = -1; | |
207 | ||
208 | #if defined(WEXITSTATUS) && defined(WIFEXITED) | |
209 | if ((pid > 0) && WIFEXITED(status)) | |
210 | return WEXITSTATUS(status); | |
211 | ||
212 | return -1; | |
213 | #else /* defined(WEXITSTATUS) && defined(WIFEXITED) */ | |
214 | return (pid == -1 ? -1 : status.w_status); | |
215 | #endif /* defined(WEXITSTATUS) && defined(WIFEXITED) */ | |
216 | } |