Commit | Line | Data |
---|---|---|
761330fe DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
0c5f72fb KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
acfc7e9b KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
761330fe DF |
16 | */ |
17 | ||
acfc7e9b | 18 | #ifndef lint |
470c33f3 | 19 | static char sccsid[] = "@(#)popen.c 5.13 (Berkeley) %G%"; |
acfc7e9b | 20 | #endif /* not lint */ |
bbbe213d | 21 | |
9650997e | 22 | #include "rcv.h" |
828615a1 | 23 | #include <sys/signal.h> |
828615a1 | 24 | #include <sys/wait.h> |
828615a1 | 25 | |
d33aa50d EW |
26 | #define READ 0 |
27 | #define WRITE 1 | |
e4920814 | 28 | static int *pid; |
ea394d88 | 29 | |
e343f97a | 30 | FILE * |
d33aa50d EW |
31 | Popen(cmd, mode) |
32 | char *cmd; | |
33 | char *mode; | |
e343f97a KS |
34 | { |
35 | int p[2]; | |
d33aa50d | 36 | int myside, hisside, fd0, fd1; |
e343f97a | 37 | |
e4920814 | 38 | if (pid == 0) |
d33aa50d | 39 | pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize()); |
9650997e | 40 | if (pipe(p) < 0) |
e343f97a | 41 | return NULL; |
d33aa50d EW |
42 | if (*mode == 'r') { |
43 | myside = p[READ]; | |
44 | fd0 = -1; | |
45 | hisside = fd1 = p[WRITE]; | |
46 | } else { | |
47 | myside = p[WRITE]; | |
48 | hisside = fd0 = p[READ]; | |
49 | fd1 = -1; | |
e343f97a | 50 | } |
d33aa50d EW |
51 | if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) { |
52 | close(p[READ]); | |
53 | close(p[WRITE]); | |
e343f97a | 54 | return NULL; |
d33aa50d | 55 | } |
e343f97a | 56 | close(hisside); |
9650997e | 57 | return fdopen(myside, mode); |
e343f97a KS |
58 | } |
59 | ||
d96977db | 60 | Pclose(ptr) |
d33aa50d | 61 | FILE *ptr; |
e343f97a | 62 | { |
d33aa50d | 63 | int i; |
828615a1 | 64 | int omask; |
e343f97a | 65 | |
d33aa50d | 66 | i = fileno(ptr); |
e343f97a | 67 | fclose(ptr); |
d33aa50d | 68 | omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); |
322c8626 | 69 | i = wait_child(pid[i]); |
4bc721c3 | 70 | sigsetmask(omask); |
d33aa50d EW |
71 | return i; |
72 | } | |
73 | ||
74 | /* | |
75 | * Run a command without a shell, with optional arguments and splicing | |
76 | * of stdin and stdout. The command name can be a sequence of words. | |
77 | * Signals must be handled by the caller. | |
78 | * "Mask" contains the signals to ignore in the new process. | |
79 | * SIGINT is enabled unless it's in the mask. | |
80 | */ | |
81 | /*VARARGS4*/ | |
82 | run_command(cmd, mask, infd, outfd, a0, a1, a2) | |
83 | char *cmd; | |
322c8626 | 84 | int mask, infd, outfd; |
d33aa50d EW |
85 | char *a0, *a1, *a2; |
86 | { | |
87 | int pid; | |
88 | ||
89 | if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) | |
90 | return -1; | |
91 | return wait_command(pid); | |
92 | } | |
93 | ||
94 | /*VARARGS4*/ | |
95 | start_command(cmd, mask, infd, outfd, a0, a1, a2) | |
96 | char *cmd; | |
322c8626 | 97 | int mask, infd, outfd; |
d33aa50d EW |
98 | char *a0, *a1, *a2; |
99 | { | |
100 | int pid; | |
101 | ||
102 | if ((pid = vfork()) < 0) { | |
103 | perror("fork"); | |
104 | return -1; | |
105 | } | |
106 | if (pid == 0) { | |
107 | char *argv[100]; | |
108 | int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); | |
109 | ||
110 | if ((argv[i++] = a0) != NOSTR && | |
111 | (argv[i++] = a1) != NOSTR && | |
112 | (argv[i++] = a2) != NOSTR) | |
113 | argv[i] = NOSTR; | |
322c8626 | 114 | prepare_child(mask, infd, outfd); |
d33aa50d EW |
115 | execvp(argv[0], argv); |
116 | perror(argv[0]); | |
117 | _exit(1); | |
118 | } | |
119 | return pid; | |
120 | } | |
121 | ||
322c8626 EW |
122 | prepare_child(mask, infd, outfd) |
123 | int mask, infd, outfd; | |
124 | { | |
125 | int i; | |
126 | ||
127 | if (infd >= 0) | |
128 | dup2(infd, 0); | |
129 | if (outfd >= 0) | |
130 | dup2(outfd, 1); | |
131 | for (i = getdtablesize(); --i > 2;) | |
132 | close(i); | |
133 | for (i = 1; i <= NSIG; i++) | |
134 | if (mask & sigmask(i)) | |
135 | (void) signal(i, SIG_IGN); | |
136 | if ((mask & sigmask(SIGINT)) == 0) | |
137 | (void) signal(SIGINT, SIG_DFL); | |
138 | (void) sigsetmask(0); | |
139 | } | |
140 | ||
d33aa50d EW |
141 | wait_command(pid) |
142 | int pid; | |
143 | { | |
d33aa50d | 144 | |
322c8626 | 145 | if (wait_child(pid) < 0) { |
d33aa50d EW |
146 | printf("Fatal error in process.\n"); |
147 | return -1; | |
148 | } | |
149 | return 0; | |
e343f97a | 150 | } |
322c8626 EW |
151 | |
152 | struct child { | |
153 | int pid; | |
154 | char done; | |
155 | char free; | |
156 | union wait status; | |
157 | struct child *link; | |
158 | }; | |
159 | static struct child *child; | |
160 | ||
161 | struct child * | |
162 | findchild(pid) | |
163 | int pid; | |
164 | { | |
165 | register struct child **cpp; | |
166 | ||
167 | for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; | |
168 | cpp = &(*cpp)->link) | |
169 | ; | |
170 | if (*cpp == NULL) { | |
171 | *cpp = (struct child *) malloc(sizeof (struct child)); | |
172 | (*cpp)->pid = pid; | |
173 | (*cpp)->done = (*cpp)->free = 0; | |
174 | (*cpp)->link = NULL; | |
175 | } | |
176 | return *cpp; | |
177 | } | |
178 | ||
179 | delchild(cp) | |
180 | register struct child *cp; | |
181 | { | |
182 | register struct child **cpp; | |
183 | ||
184 | for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) | |
185 | ; | |
186 | *cpp = cp->link; | |
187 | free((char *) cp); | |
188 | } | |
189 | ||
190 | sigchild() | |
191 | { | |
192 | int pid; | |
193 | union wait status; | |
194 | register struct child *cp; | |
195 | ||
196 | while ((pid = wait3(&status, WNOHANG, (struct timeval *)0)) > 0) { | |
197 | cp = findchild(pid); | |
198 | if (cp->free) | |
199 | delchild(cp); | |
200 | else { | |
201 | cp->done = 1; | |
202 | cp->status = status; | |
203 | } | |
204 | } | |
205 | } | |
206 | ||
207 | union wait wait_status; | |
208 | ||
209 | /* | |
210 | * Wait for a specific child to die. | |
211 | */ | |
212 | wait_child(pid) | |
213 | int pid; | |
214 | { | |
215 | int mask = sigblock(sigmask(SIGCHLD)); | |
216 | register struct child *cp = findchild(pid); | |
217 | ||
218 | while (!cp->done) | |
219 | sigpause(mask); | |
220 | wait_status = cp->status; | |
221 | delchild(cp); | |
222 | sigsetmask(mask); | |
223 | return wait_status.w_status ? -1 : 0; | |
224 | } | |
225 | ||
226 | /* | |
227 | * Mark a child as don't care. | |
228 | */ | |
229 | free_child(pid) | |
230 | int pid; | |
231 | { | |
232 | int mask = sigblock(sigmask(SIGCHLD)); | |
233 | register struct child *cp = findchild(pid); | |
234 | ||
235 | if (cp->done) | |
236 | delchild(cp); | |
237 | else | |
238 | cp->free = 1; | |
239 | sigsetmask(mask); | |
240 | } |