popen.c revision 1.19 1 /* $NetBSD: popen.c,v 1.19 2005/07/19 23:07:10 christos 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.19 2005/07/19 23:07:10 christos 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(const char *, sigset_t *, int, int, va_list);
72
73 FILE *
74 Fopen(const char *fn, const 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, const 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(const char *cmd, const 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 (void)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 (void)sigemptyset(&nset);
149 (void)sigaddset(&nset, SIGINT);
150 (void)sigaddset(&nset, SIGHUP);
151 (void)sigprocmask(SIG_BLOCK, &nset, &oset);
152 i = wait_child(i);
153 (void)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(const char *cmd, sigset_t *nset, int infd, int outfd,
218 va_list args)
219 {
220 pid_t pid;
221
222 if ((pid = fork()) < 0) {
223 warn("fork");
224 return -1;
225 }
226 if (pid == 0) {
227 char *argv[100];
228 int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv));
229
230 while ((argv[i++] = va_arg(args, char *)) != NULL)
231 continue;
232 argv[i] = NULL;
233 prepare_child(nset, infd, outfd);
234 (void)execvp(argv[0], argv);
235 warn("%s", argv[0]);
236 _exit(1);
237 }
238 return pid;
239 }
240
241 int
242 run_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...)
243 {
244 pid_t pid;
245 va_list args;
246
247 va_start(args, outfd);
248 pid = start_commandv(cmd, nset, infd, outfd, args);
249 va_end(args);
250 if (pid < 0)
251 return -1;
252 return wait_command(pid);
253 }
254
255 int
256 start_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...)
257 {
258 va_list args;
259 int r;
260
261 va_start(args, outfd);
262 r = start_commandv(cmd, nset, infd, outfd, args);
263 va_end(args);
264 return r;
265 }
266
267 void
268 prepare_child(sigset_t *nset, int infd, int outfd)
269 {
270 int i;
271 sigset_t eset;
272
273 /*
274 * All file descriptors other than 0, 1, and 2 are supposed to be
275 * close-on-exec.
276 */
277 if (infd > 0) {
278 (void)dup2(infd, 0);
279 } else if (infd != 0) {
280 /* we don't want the child stealing my stdin input */
281 (void)close(0);
282 (void)open(_PATH_DEVNULL, O_RDONLY, 0);
283 }
284 if (outfd >= 0 && outfd != 1)
285 (void)dup2(outfd, 1);
286 if (nset == NULL)
287 return;
288 if (nset != NULL) {
289 for (i = 1; i < NSIG; i++)
290 if (sigismember(nset, i))
291 (void)signal(i, SIG_IGN);
292 }
293 if (nset == NULL || !sigismember(nset, SIGINT))
294 (void)signal(SIGINT, SIG_DFL);
295 (void)sigemptyset(&eset);
296 (void)sigprocmask(SIG_SETMASK, &eset, NULL);
297 }
298
299 int
300 wait_command(pid_t pid)
301 {
302
303 if (wait_child(pid) < 0) {
304 (void)puts("Fatal error in process.");
305 return -1;
306 }
307 return 0;
308 }
309
310 static struct child *
311 findchild(pid_t pid, int dont_alloc)
312 {
313 struct child **cpp;
314
315 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
316 cpp = &(*cpp)->link)
317 ;
318 if (*cpp == NULL) {
319 if (dont_alloc)
320 return NULL;
321 if (child_freelist) {
322 *cpp = child_freelist;
323 child_freelist = (*cpp)->link;
324 } else {
325 *cpp = (struct child *)malloc(sizeof(struct child));
326 if (*cpp == NULL)
327 errx(1, "Out of memory");
328 }
329 (*cpp)->pid = pid;
330 (*cpp)->done = (*cpp)->free = 0;
331 (*cpp)->link = NULL;
332 }
333 return *cpp;
334 }
335
336 static void
337 delchild(struct child *cp)
338 {
339 struct child **cpp;
340
341 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
342 ;
343 *cpp = cp->link;
344 cp->link = child_freelist;
345 child_freelist = cp;
346 }
347
348 void
349 /*ARGSUSED*/
350 sigchild(int signo)
351 {
352 pid_t pid;
353 int status;
354 struct child *cp;
355 int save_errno = errno;
356
357 while ((pid =
358 waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
359 cp = findchild(pid, 1);
360 if (!cp)
361 continue;
362 if (cp->free)
363 delchild(cp);
364 else {
365 cp->done = 1;
366 cp->status = status;
367 }
368 }
369 errno = save_errno;
370 }
371
372 int wait_status;
373
374 /*
375 * Wait for a specific child to die.
376 */
377 int
378 wait_child(pid_t pid)
379 {
380 struct child *cp;
381 sigset_t nset, oset;
382 pid_t rv = 0;
383
384 (void)sigemptyset(&nset);
385 (void)sigaddset(&nset, SIGCHLD);
386 (void)sigprocmask(SIG_BLOCK, &nset, &oset);
387 /*
388 * If we have not already waited on the pid (via sigchild)
389 * wait on it now. Otherwise, use the wait status stashed
390 * by sigchild.
391 */
392 cp = findchild(pid, 1);
393 if (cp == NULL || !cp->done)
394 rv = waitpid(pid, &wait_status, 0);
395 else
396 wait_status = cp->status;
397 if (cp != NULL)
398 delchild(cp);
399 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
400 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status)))
401 return -1;
402 else
403 return 0;
404 }
405
406 /*
407 * Mark a child as don't care.
408 */
409 void
410 free_child(pid_t pid)
411 {
412 struct child *cp;
413 sigset_t nset, oset;
414
415 (void)sigemptyset(&nset);
416 (void)sigaddset(&nset, SIGCHLD);
417 (void)sigprocmask(SIG_BLOCK, &nset, &oset);
418 if ((cp = findchild(pid, 0)) != NULL) {
419 if (cp->done)
420 delchild(cp);
421 else
422 cp->free = 1;
423 }
424 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
425 }
426