1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include "rcv.h"
13 #include <sys/wait.h>
14 #include <fcntl.h>
15 #include "extern.h"
16
17 #define READ 0
18 #define WRITE 1
19
20 struct fp {
21 FILE *fp;
22 int pipe;
23 int pid;
24 struct fp *link;
25 };
26 static struct fp *fp_head;
27
28 struct child {
29 int pid;
30 char done;
31 char free;
32 union wait status;
33 struct child *link;
34 };
35 static struct child *child;
36 static struct child *findchild __P((int));
37 static void delchild __P((struct child *));
38
39 FILE *
Fopen(file,mode)40 Fopen(file, mode)
41 char *file, *mode;
42 {
43 FILE *fp;
44
45 if ((fp = fopen(file, mode)) != NULL) {
46 register_file(fp, 0, 0);
47 (void) fcntl(fileno(fp), F_SETFD, 1);
48 }
49 return fp;
50 }
51
52 FILE *
Fdopen(fd,mode)53 Fdopen(fd, mode)
54 int fd;
55 char *mode;
56 {
57 FILE *fp;
58
59 if ((fp = fdopen(fd, mode)) != NULL) {
60 register_file(fp, 0, 0);
61 (void) fcntl(fileno(fp), F_SETFD, 1);
62 }
63 return fp;
64 }
65
66 int
Fclose(fp)67 Fclose(fp)
68 FILE *fp;
69 {
70 unregister_file(fp);
71 return fclose(fp);
72 }
73
74 FILE *
Popen(cmd,mode)75 Popen(cmd, mode)
76 char *cmd;
77 char *mode;
78 {
79 int p[2];
80 int myside, hisside, fd0, fd1;
81 int pid;
82 FILE *fp;
83
84 if (pipe(p) < 0)
85 return NULL;
86 (void) fcntl(p[READ], F_SETFD, 1);
87 (void) fcntl(p[WRITE], F_SETFD, 1);
88 if (*mode == 'r') {
89 myside = p[READ];
90 fd0 = -1;
91 hisside = fd1 = p[WRITE];
92 } else {
93 myside = p[WRITE];
94 hisside = fd0 = p[READ];
95 fd1 = -1;
96 }
97 if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) {
98 close(p[READ]);
99 close(p[WRITE]);
100 return NULL;
101 }
102 (void) close(hisside);
103 if ((fp = fdopen(myside, mode)) != NULL)
104 register_file(fp, 1, pid);
105 return fp;
106 }
107
108 int
Pclose(ptr)109 Pclose(ptr)
110 FILE *ptr;
111 {
112 int i;
113 int omask;
114
115 i = file_pid(ptr);
116 unregister_file(ptr);
117 (void) fclose(ptr);
118 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
119 i = wait_child(i);
120 sigsetmask(omask);
121 return i;
122 }
123
124 void
close_all_files()125 close_all_files()
126 {
127
128 while (fp_head)
129 if (fp_head->pipe)
130 (void) Pclose(fp_head->fp);
131 else
132 (void) Fclose(fp_head->fp);
133 }
134
135 void
register_file(fp,pipe,pid)136 register_file(fp, pipe, pid)
137 FILE *fp;
138 int pipe, pid;
139 {
140 struct fp *fpp;
141
142 if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL)
143 panic("Out of memory");
144 fpp->fp = fp;
145 fpp->pipe = pipe;
146 fpp->pid = pid;
147 fpp->link = fp_head;
148 fp_head = fpp;
149 }
150
151 void
unregister_file(fp)152 unregister_file(fp)
153 FILE *fp;
154 {
155 struct fp **pp, *p;
156
157 for (pp = &fp_head; p = *pp; pp = &p->link)
158 if (p->fp == fp) {
159 *pp = p->link;
160 free((char *) p);
161 return;
162 }
163 panic("Invalid file pointer");
164 }
165
file_pid(fp)166 file_pid(fp)
167 FILE *fp;
168 {
169 struct fp *p;
170
171 for (p = fp_head; p; p = p->link)
172 if (p->fp == fp)
173 return (p->pid);
174 panic("Invalid file pointer");
175 /*NOTREACHED*/
176 }
177
178 /*
179 * Run a command without a shell, with optional arguments and splicing
180 * of stdin and stdout. The command name can be a sequence of words.
181 * Signals must be handled by the caller.
182 * "Mask" contains the signals to ignore in the new process.
183 * SIGINT is enabled unless it's in the mask.
184 */
185 /*VARARGS4*/
186 int
run_command(cmd,mask,infd,outfd,a0,a1,a2)187 run_command(cmd, mask, infd, outfd, a0, a1, a2)
188 char *cmd;
189 int mask, infd, outfd;
190 char *a0, *a1, *a2;
191 {
192 int pid;
193
194 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
195 return -1;
196 return wait_command(pid);
197 }
198
199 /*VARARGS4*/
200 int
start_command(cmd,mask,infd,outfd,a0,a1,a2)201 start_command(cmd, mask, infd, outfd, a0, a1, a2)
202 char *cmd;
203 int mask, infd, outfd;
204 char *a0, *a1, *a2;
205 {
206 int pid;
207
208 if ((pid = vfork()) < 0) {
209 perror("fork");
210 return -1;
211 }
212 if (pid == 0) {
213 char *argv[100];
214 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv);
215
216 if ((argv[i++] = a0) != NOSTR &&
217 (argv[i++] = a1) != NOSTR &&
218 (argv[i++] = a2) != NOSTR)
219 argv[i] = NOSTR;
220 prepare_child(mask, infd, outfd);
221 execvp(argv[0], argv);
222 perror(argv[0]);
223 _exit(1);
224 }
225 return pid;
226 }
227
228 void
prepare_child(mask,infd,outfd)229 prepare_child(mask, infd, outfd)
230 int mask, infd, outfd;
231 {
232 int i;
233
234 /*
235 * All file descriptors other than 0, 1, and 2 are supposed to be
236 * close-on-exec.
237 */
238 if (infd >= 0)
239 dup2(infd, 0);
240 if (outfd >= 0)
241 dup2(outfd, 1);
242 for (i = 1; i <= NSIG; i++)
243 if (mask & sigmask(i))
244 (void) signal(i, SIG_IGN);
245 if ((mask & sigmask(SIGINT)) == 0)
246 (void) signal(SIGINT, SIG_DFL);
247 (void) sigsetmask(0);
248 }
249
250 int
wait_command(pid)251 wait_command(pid)
252 int pid;
253 {
254
255 if (wait_child(pid) < 0) {
256 printf("Fatal error in process.\n");
257 return -1;
258 }
259 return 0;
260 }
261
262 static struct child *
findchild(pid)263 findchild(pid)
264 int pid;
265 {
266 register struct child **cpp;
267
268 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
269 cpp = &(*cpp)->link)
270 ;
271 if (*cpp == NULL) {
272 *cpp = (struct child *) malloc(sizeof (struct child));
273 (*cpp)->pid = pid;
274 (*cpp)->done = (*cpp)->free = 0;
275 (*cpp)->link = NULL;
276 }
277 return *cpp;
278 }
279
280 static void
delchild(cp)281 delchild(cp)
282 register struct child *cp;
283 {
284 register struct child **cpp;
285
286 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
287 ;
288 *cpp = cp->link;
289 free((char *) cp);
290 }
291
292 void
sigchild(signo)293 sigchild(signo)
294 int signo;
295 {
296 int pid;
297 union wait status;
298 register struct child *cp;
299
300 while ((pid =
301 wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) {
302 cp = findchild(pid);
303 if (cp->free)
304 delchild(cp);
305 else {
306 cp->done = 1;
307 cp->status = status;
308 }
309 }
310 }
311
312 union wait wait_status;
313
314 /*
315 * Wait for a specific child to die.
316 */
317 int
wait_child(pid)318 wait_child(pid)
319 int pid;
320 {
321 int mask = sigblock(sigmask(SIGCHLD));
322 register struct child *cp = findchild(pid);
323
324 while (!cp->done)
325 sigpause(mask);
326 wait_status = cp->status;
327 delchild(cp);
328 sigsetmask(mask);
329 return wait_status.w_status ? -1 : 0;
330 }
331
332 /*
333 * Mark a child as don't care.
334 */
335 void
free_child(pid)336 free_child(pid)
337 int pid;
338 {
339 int mask = sigblock(sigmask(SIGCHLD));
340 register struct child *cp = findchild(pid);
341
342 if (cp->done)
343 delchild(cp);
344 else
345 cp->free = 1;
346 sigsetmask(mask);
347 }
348