1 /* $NetBSD: popen.c,v 1.24 2007/10/30 02:28:31 christos Exp $ */
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93";
37 __RCSID("$NetBSD: popen.c,v 1.24 2007/10/30 02:28:31 christos Exp $");
60 static struct fp
*fp_head
;
69 static struct child
*child
, *child_freelist
= NULL
;
72 #if 0 /* XXX - debugging stuff. This should go away eventually! */
74 show_one_file(FILE *fo
, struct fp
*fpp
)
76 (void)fprintf(fo
, ">>> fp: %p, pipe: %d, pid: %d, link: %p\n",
77 fpp
->fp
, fpp
->pipe
, fpp
->pid
, fpp
->link
);
80 void show_all_files(FILE *fo
);
83 show_all_files(FILE *fo
)
87 (void)fprintf(fo
, ">> FILES\n");
88 for (fpp
= fp_head
; fpp
; fpp
= fpp
->link
)
89 show_one_file(fo
, fpp
);
90 (void)fprintf(fo
, ">> -------\n");
93 #endif /* end debugging stuff */
97 unregister_file(FILE *fp
)
101 for (pp
= &fp_head
; (p
= *pp
) != NULL
; pp
= &p
->link
)
107 errx(1, "Invalid file pointer");
111 register_file(FILE *fp
, int pipefd
, pid_t pid
)
115 fpp
= emalloc(sizeof(*fpp
));
124 Fopen(const char *fn
, const char *mode
)
128 if ((fp
= fopen(fn
, mode
)) != NULL
) {
129 register_file(fp
, 0, 0);
130 (void)fcntl(fileno(fp
), F_SETFD
, FD_CLOEXEC
);
136 Fdopen(int fd
, const char *mode
)
140 if ((fp
= fdopen(fd
, mode
)) != NULL
) {
141 register_file(fp
, 0, 0);
142 (void)fcntl(fileno(fp
), F_SETFD
, FD_CLOEXEC
);
159 prepare_child(sigset_t
*nset
, int infd
, int outfd
)
165 * All file descriptors other than 0, 1, and 2 are supposed to be
170 } else if (infd
!= 0) {
171 /* we don't want the child stealing my stdin input */
173 (void)open(_PATH_DEVNULL
, O_RDONLY
, 0);
175 if (outfd
>= 0 && outfd
!= 1)
176 (void)dup2(outfd
, 1);
179 for (i
= 1; i
< NSIG
; i
++) {
180 if (sigismember(nset
, i
))
181 (void)signal(i
, SIG_IGN
);
183 if (!sigismember(nset
, SIGINT
))
184 (void)signal(SIGINT
, SIG_DFL
);
185 (void)sigemptyset(&eset
);
186 (void)sigprocmask(SIG_SETMASK
, &eset
, NULL
);
191 * Run a command without a shell, with optional arguments and splicing
192 * of stdin (-1 means none) and stdout. The command name can be a sequence
194 * Signals must be handled by the caller.
195 * "nset" contains the signals to ignore in the new process.
196 * SIGINT is enabled unless it's in "nset".
199 start_commandv(const char *cmd
, sigset_t
*nset
, int infd
, int outfd
,
205 if ((pid
= fork()) < 0) {
213 i
= getrawlist(cmd
, argv
, (int)__arraycount(argv
));
214 while (i
< __arraycount(argv
) - 1 &&
215 (argv
[i
++] = va_arg(args
, char *)) != NULL
)
218 prepare_child(nset
, infd
, outfd
);
219 (void)execvp(argv
[0], argv
);
227 start_command(const char *cmd
, sigset_t
*nset
, int infd
, int outfd
, ...)
232 va_start(args
, outfd
);
233 r
= start_commandv(cmd
, nset
, infd
, outfd
, args
);
239 Popen(const char *cmd
, const char *mode
)
242 int myside
, hisside
, fd0
, fd1
;
250 (void)fcntl(p
[READ
], F_SETFD
, FD_CLOEXEC
);
251 (void)fcntl(p
[WRITE
], F_SETFD
, FD_CLOEXEC
);
254 hisside
= fd0
= fd1
= p
[WRITE
];
257 hisside
= fd0
= p
[READ
];
260 (void)sigemptyset(&nset
);
261 if ((shellcmd
= value(ENAME_SHELL
)) == NULL
)
262 shellcmd
= __UNCONST(_PATH_CSHELL
);
263 pid
= start_command(shellcmd
, &nset
, fd0
, fd1
, "-c", cmd
, NULL
);
265 (void)close(p
[READ
]);
266 (void)close(p
[WRITE
]);
269 (void)close(hisside
);
270 if ((fp
= fdopen(myside
, mode
)) != NULL
)
271 register_file(fp
, 1, pid
);
275 static struct child
*
276 findchild(pid_t pid
, int dont_alloc
)
280 for (cpp
= &child
; *cpp
!= NULL
&& (*cpp
)->pid
!= pid
;
286 if (child_freelist
) {
287 *cpp
= child_freelist
;
288 child_freelist
= (*cpp
)->link
;
290 *cpp
= emalloc(sizeof(**cpp
));
293 (*cpp
)->done
= (*cpp
)->free
= 0;
300 delchild(struct child
*cp
)
304 for (cpp
= &child
; *cpp
!= cp
; cpp
= &(*cpp
)->link
)
307 cp
->link
= child_freelist
;
312 * Wait for a specific child to die.
315 wait_child(pid_t pid
)
321 (void)sigemptyset(&nset
);
322 (void)sigaddset(&nset
, SIGCHLD
);
323 (void)sigprocmask(SIG_BLOCK
, &nset
, &oset
);
325 * If we have not already waited on the pid (via sigchild)
326 * wait on it now. Otherwise, use the wait status stashed
329 cp
= findchild(pid
, 1);
330 if (cp
== NULL
|| !cp
->done
)
331 rv
= waitpid(pid
, &wait_status
, 0);
333 wait_status
= cp
->status
;
336 (void)sigprocmask(SIG_SETMASK
, &oset
, NULL
);
337 if (rv
== -1 || (WIFEXITED(wait_status
) && WEXITSTATUS(wait_status
)))
348 for (p
= fp_head
; p
; p
= p
->link
)
351 errx(1, "Invalid file pointer");
365 unregister_file(ptr
);
367 (void)sigemptyset(&nset
);
368 (void)sigaddset(&nset
, SIGINT
);
369 (void)sigaddset(&nset
, SIGHUP
);
370 (void)sigprocmask(SIG_BLOCK
, &nset
, &oset
);
372 (void)sigprocmask(SIG_SETMASK
, &oset
, NULL
);
377 close_all_files(void)
381 (void)Pclose(fp_head
->fp
);
383 (void)Fclose(fp_head
->fp
);
387 last_registered_file(int last_pipe
)
392 return fp_head
? fp_head
->fp
: NULL
;
394 for (fpp
= fp_head
; fpp
; fpp
= fpp
->link
)
401 close_top_files(FILE *fp_stop
)
403 while (fp_head
&& fp_head
->fp
!= fp_stop
)
405 (void)Pclose(fp_head
->fp
);
407 (void)Fclose(fp_head
->fp
);
412 flush_files(FILE *fo
, int only_pipes
)
419 for (fpp
= fp_head
; fpp
; fpp
= fpp
->link
)
420 if (!only_pipes
|| fpp
->pipe
)
421 (void)fflush(fpp
->fp
);
423 (void)fflush(stdout
);
425 #endif /* MIME_SUPPORT */
428 wait_command(pid_t pid
)
431 if (wait_child(pid
) < 0) {
432 (void)puts("Fatal error in process.");
439 run_command(const char *cmd
, sigset_t
*nset
, int infd
, int outfd
, ...)
445 #ifdef BROKEN_EXEC_TTY_RESTORE
446 struct termios ttybuf
;
449 * XXX - grab the tty settings as currently they can get
450 * trashed by emacs-21 when suspending with bash-3.2.25 as the
453 * 1) from the mail editor, start "emacs -nw" (21.4)
454 * 2) suspend emacs to the shell (bash 3.2.25)
456 * 4) exit emacs back to the mail editor
457 * 5) discover the tty is screwed: the mail editor is no
458 * longer receiving characters
460 * - This occurs on both i386 and amd64.
461 * - This did _NOT_ occur before 4.99.10.
462 * - This does _NOT_ occur if the editor is vi(1) or if the shell
464 * - This _DOES_ happen with the old mail(1) from 2006-01-01 (long
465 * before my changes).
467 * This is the commit that introduced this "feature":
468 * http://mail-index.netbsd.org/source-changes/2007/02/09/0020.html
470 if ((tcrval
= tcgetattr(fileno(stdin
), &ttybuf
)) == -1)
473 va_start(args
, outfd
);
474 pid
= start_commandv(cmd
, nset
, infd
, outfd
, args
);
478 rval
= wait_command(pid
);
479 #ifdef BROKEN_EXEC_TTY_RESTORE
480 if (tcrval
!= -1 && tcsetattr(fileno(stdin
), TCSADRAIN
, &ttybuf
) == -1)
489 sigchild(int signo __unused
)
497 while ((pid
= waitpid((pid_t
)-1, &status
, WNOHANG
)) > 0) {
498 cp
= findchild(pid
, 1); /* async-signal-safe: we don't alloc */
502 delchild(cp
); /* async-signal-safe: list changes */
512 * Mark a child as don't care.
515 free_child(pid_t pid
)
520 (void)sigemptyset(&nset
);
521 (void)sigaddset(&nset
, SIGCHLD
);
522 (void)sigprocmask(SIG_BLOCK
, &nset
, &oset
);
523 if ((cp
= findchild(pid
, 0)) != NULL
) {
529 (void)sigprocmask(SIG_SETMASK
, &oset
, NULL
);