popen.c revision 1.17 1 /* $NetBSD: popen.c,v 1.17 2003/08/07 11:14:40 agc Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93";
36 #else
37 __RCSID("$NetBSD: popen.c,v 1.17 2003/08/07 11:14:40 agc Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include "rcv.h"
42 #include <sys/wait.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <stdarg.h>
46 #include "extern.h"
47
48 #define READ 0
49 #define WRITE 1
50
51 struct fp {
52 FILE *fp;
53 int pipe;
54 pid_t pid;
55 struct fp *link;
56 };
57 static struct fp *fp_head;
58
59 struct child {
60 pid_t pid;
61 char done;
62 char free;
63 int status;
64 struct child *link;
65 };
66 static struct child *child, *child_freelist = NULL;
67
68 static struct child *findchild(pid_t, int);
69 static void delchild(struct child *);
70 static pid_t file_pid(FILE *);
71 static pid_t start_commandv(char *, sigset_t *, int, int, va_list);
72
73 FILE *
74 Fopen(char *fn, char *mode)
75 {
76 FILE *fp;
77
78 if ((fp = fopen(fn, mode)) != NULL) {
79 register_file(fp, 0, 0);
80 (void)fcntl(fileno(fp), F_SETFD, 1);
81 }
82 return fp;
83 }
84
85 FILE *
86 Fdopen(int fd, char *mode)
87 {
88 FILE *fp;
89
90 if ((fp = fdopen(fd, mode)) != NULL) {
91 register_file(fp, 0, 0);
92 (void)fcntl(fileno(fp), F_SETFD, 1);
93 }
94 return fp;
95 }
96
97 int
98 Fclose(FILE *fp)
99 {
100
101 unregister_file(fp);
102 return fclose(fp);
103 }
104
105 FILE *
106 Popen(char *cmd, char *mode)
107 {
108 int p[2];
109 int myside, hisside, fd0, fd1;
110 pid_t pid;
111 sigset_t nset;
112 FILE *fp;
113
114 if (pipe(p) < 0)
115 return NULL;
116 (void)fcntl(p[READ], F_SETFD, 1);
117 (void)fcntl(p[WRITE], F_SETFD, 1);
118 if (*mode == 'r') {
119 myside = p[READ];
120 hisside = fd0 = fd1 = p[WRITE];
121 } else {
122 myside = p[WRITE];
123 hisside = fd0 = p[READ];
124 fd1 = -1;
125 }
126 sigemptyset(&nset);
127 pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL);
128 if (pid < 0) {
129 (void)close(p[READ]);
130 (void)close(p[WRITE]);
131 return NULL;
132 }
133 (void)close(hisside);
134 if ((fp = fdopen(myside, mode)) != NULL)
135 register_file(fp, 1, pid);
136 return fp;
137 }
138
139 int
140 Pclose(FILE *ptr)
141 {
142 int i;
143 sigset_t nset, oset;
144
145 i = file_pid(ptr);
146 unregister_file(ptr);
147 (void)fclose(ptr);
148 sigemptyset(&nset);
149 sigaddset(&nset, SIGINT);
150 sigaddset(&nset, SIGHUP);
151 sigprocmask(SIG_BLOCK, &nset, &oset);
152 i = wait_child(i);
153 sigprocmask(SIG_SETMASK, &oset, NULL);
154 return i;
155 }
156
157 void
158 close_all_files(void)
159 {
160
161 while (fp_head)
162 if (fp_head->pipe)
163 (void)Pclose(fp_head->fp);
164 else
165 (void)Fclose(fp_head->fp);
166 }
167
168 void
169 register_file(FILE *fp, int pipefd, pid_t pid)
170 {
171 struct fp *fpp;
172
173 if ((fpp = (struct fp *)malloc(sizeof(*fpp))) == NULL)
174 errx(1, "Out of memory");
175 fpp->fp = fp;
176 fpp->pipe = pipefd;
177 fpp->pid = pid;
178 fpp->link = fp_head;
179 fp_head = fpp;
180 }
181
182 void
183 unregister_file(FILE *fp)
184 {
185 struct fp **pp, *p;
186
187 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
188 if (p->fp == fp) {
189 *pp = p->link;
190 (void)free(p);
191 return;
192 }
193 errx(1, "Invalid file pointer");
194 }
195
196 static pid_t
197 file_pid(FILE *fp)
198 {
199 struct fp *p;
200
201 for (p = fp_head; p; p = p->link)
202 if (p->fp == fp)
203 return p->pid;
204 errx(1, "Invalid file pointer");
205 /*NOTREACHED*/
206 }
207
208 /*
209 * Run a command without a shell, with optional arguments and splicing
210 * of stdin (-1 means none) and stdout. The command name can be a sequence
211 * of words.
212 * Signals must be handled by the caller.
213 * "nset" contains the signals to ignore in the new process.
214 * SIGINT is enabled unless it's in "nset".
215 */
216 static pid_t
217 start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args)
218 {
219 pid_t pid;
220
221 if ((pid = fork()) < 0) {
222 warn("fork");
223 return -1;
224 }
225 if (pid == 0) {
226 char *argv[100];
227 int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv));
228
229 while ((argv[i++] = va_arg(args, char *)))
230 ;
231 argv[i] = NULL;
232 prepare_child(nset, infd, outfd);
233 execvp(argv[0], argv);
234 warn("%s", argv[0]);
235 _exit(1);
236 }
237 return pid;
238 }
239
240 int
241 run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
242 {
243 pid_t pid;
244 va_list args;
245
246 va_start(args, outfd);
247 pid = start_commandv(cmd, nset, infd, outfd, args);
248 va_end(args);
249 if (pid < 0)
250 return -1;
251 return wait_command(pid);
252 }
253
254 int
255 start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...)
256 {
257 va_list args;
258 int r;
259
260 va_start(args, outfd);
261 r = start_commandv(cmd, nset, infd, outfd, args);
262 va_end(args);
263 return r;
264 }
265
266 void
267 prepare_child(sigset_t *nset, int infd, int outfd)
268 {
269 int i;
270 sigset_t eset;
271
272 /*
273 * All file descriptors other than 0, 1, and 2 are supposed to be
274 * close-on-exec.
275 */
276 if (infd > 0) {
277 dup2(infd, 0);
278 } else if (infd != 0) {
279 /* we don't want the child stealing my stdin input */
280 close(0);
281 open(_PATH_DEVNULL, O_RDONLY, 0);
282 }
283 if (outfd >= 0 && outfd != 1)
284 dup2(outfd, 1);
285 if (nset == NULL)
286 return;
287 if (nset != NULL) {
288 for (i = 1; i < NSIG; i++)
289 if (sigismember(nset, i))
290 (void)signal(i, SIG_IGN);
291 }
292 if (nset == NULL || !sigismember(nset, SIGINT))
293 (void)signal(SIGINT, SIG_DFL);
294 sigemptyset(&eset);
295 (void)sigprocmask(SIG_SETMASK, &eset, NULL);
296 }
297
298 int
299 wait_command(pid_t pid)
300 {
301
302 if (wait_child(pid) < 0) {
303 puts("Fatal error in process.");
304 return -1;
305 }
306 return 0;
307 }
308
309 static struct child *
310 findchild(pid_t pid, int dont_alloc)
311 {
312 struct child **cpp;
313
314 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
315 cpp = &(*cpp)->link)
316 ;
317 if (*cpp == NULL) {
318 if (dont_alloc)
319 return NULL;
320 if (child_freelist) {
321 *cpp = child_freelist;
322 child_freelist = (*cpp)->link;
323 } else {
324 *cpp = (struct child *)malloc(sizeof(struct child));
325 if (*cpp == NULL)
326 errx(1, "Out of memory");
327 }
328 (*cpp)->pid = pid;
329 (*cpp)->done = (*cpp)->free = 0;
330 (*cpp)->link = NULL;
331 }
332 return *cpp;
333 }
334
335 static void
336 delchild(struct child *cp)
337 {
338 struct child **cpp;
339
340 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
341 ;
342 *cpp = cp->link;
343 cp->link = child_freelist;
344 child_freelist = cp;
345 }
346
347 void
348 sigchild(int signo)
349 {
350 pid_t pid;
351 int status;
352 struct child *cp;
353 int save_errno = errno;
354
355 while ((pid =
356 waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
357 cp = findchild(pid, 1);
358 if (!cp)
359 continue;
360 if (cp->free)
361 delchild(cp);
362 else {
363 cp->done = 1;
364 cp->status = status;
365 }
366 }
367 errno = save_errno;
368 }
369
370 int wait_status;
371
372 /*
373 * Wait for a specific child to die.
374 */
375 int
376 wait_child(pid_t pid)
377 {
378 struct child *cp;
379 sigset_t nset, oset;
380 pid_t rv = 0;
381
382 sigemptyset(&nset);
383 sigaddset(&nset, SIGCHLD);
384 sigprocmask(SIG_BLOCK, &nset, &oset);
385 /*
386 * If we have not already waited on the pid (via sigchild)
387 * wait on it now. Otherwise, use the wait status stashed
388 * by sigchild.
389 */
390 cp = findchild(pid, 1);
391 if (cp == NULL || !cp->done)
392 rv = waitpid(pid, &wait_status, 0);
393 else
394 wait_status = cp->status;
395 if (cp != NULL)
396 delchild(cp);
397 sigprocmask(SIG_SETMASK, &oset, NULL);
398 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)))
399 return -1;
400 else
401 return 0;
402 }
403
404 /*
405 * Mark a child as don't care.
406 */
407 void
408 free_child(pid_t pid)
409 {
410 struct child *cp;
411 sigset_t nset, oset;
412
413 sigemptyset(&nset);
414 sigaddset(&nset, SIGCHLD);
415 sigprocmask(SIG_BLOCK, &nset, &oset);
416 if ((cp = findchild(pid, 0)) != NULL) {
417 if (cp->done)
418 delchild(cp);
419 else
420 cp->free = 1;
421 }
422 sigprocmask(SIG_SETMASK, &oset, NULL);
423 }
424