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