Commit | Line | Data |
---|---|---|
39af1cb3 BJ |
1 | /* Copyright (c) 1979 Regents of the University of California */ |
2 | #include "sh.h" | |
3 | ||
4 | /* | |
5 | * C shell | |
6 | */ | |
7 | ||
8 | execute(t, pipein, pipeout) | |
9 | register struct command *t; | |
10 | int *pipein, *pipeout; | |
11 | { | |
12 | int pid, flags, pv[2]; | |
13 | register struct command *t1; | |
14 | register char *cp; | |
15 | bool forked = 0; | |
16 | bool shudint, shudhup; | |
17 | #ifdef VFORK | |
18 | int (*savint)(), vffree(); | |
19 | int ochild, osetintr, ohaderr, otimflg, odidfds, odidcch; | |
20 | int oSHIN, oSHOUT, oSHDIAG, oOLDSTD; | |
21 | int isvfork = 0; | |
22 | #endif | |
23 | ||
24 | if (t == 0) | |
25 | return; | |
26 | switch (t->t_dtyp) { | |
27 | ||
28 | case TCOM: | |
29 | cp = t->t_dcom[0]; | |
30 | if ((cp[0] & (QUOTE|TRIM)) == QUOTE) | |
31 | strcpy(cp, cp + 1); | |
32 | if ((t->t_dflg & FREDO) == 0) | |
33 | Dfix(t); /* $ " ' \ */ | |
34 | /* fall into... */ | |
35 | ||
36 | case TPAR: | |
37 | flags = t->t_dflg; | |
38 | if (flags & FPOU) | |
39 | mypipe(pipeout); | |
40 | /* | |
41 | * A child will be interruptible only under very | |
42 | * certain conditions: | |
43 | * we must be monkeying with interrupts | |
44 | * the child must not be &'ed | |
45 | * we must not have had an "onintr -" | |
46 | */ | |
47 | shudint = setintr && (flags & FINT) == 0 && (!gointr || !eq(gointr, "-")); | |
48 | shudhup = (flags & FAND) == 0; | |
49 | ||
50 | /* | |
51 | * Must do << early so parent will know | |
52 | * where input pointer should be | |
53 | */ | |
54 | if (flags & FHERE) | |
55 | close(0), heredoc(t->t_dlef); | |
56 | ||
57 | /* | |
58 | * If not executing commands then | |
59 | * all we must do is read forward in the input to | |
60 | * account for << redirection if present. | |
61 | */ | |
62 | if (noexec) { | |
63 | if (flags & FHERE) | |
64 | close(0); | |
65 | return; | |
66 | } | |
67 | ||
68 | set("status", "0"); | |
69 | pid = 0; | |
70 | ||
71 | /* | |
72 | * Built-in functions | |
73 | */ | |
74 | if (t->t_dtyp == TCOM && isbfunc(t->t_dcom[0])) { | |
75 | /* | |
76 | * If output is piped, or running & and we would | |
77 | * eventually fork for non-builtin commands, | |
78 | * then do it now, so we won't block. | |
79 | */ | |
80 | if ((flags & (FPOU|FAND)) && (flags & FPAR) == 0) | |
81 | pid = dofork(shudint, shudhup), forked++; | |
82 | ||
83 | /* | |
84 | * If the builtin is actually executed (some, e.g. | |
85 | * time and nice may refuse to execute here) | |
86 | * then either exit (if we forked) or close i/o | |
87 | * and continue execution (if we didn't). | |
88 | */ | |
89 | if (pid == 0) { | |
90 | doio(t, pipein, pipeout); | |
91 | if (flags & FPOU) { | |
92 | close(pipeout[0]), close(pipeout[1]); | |
93 | pipeout[0] = pipeout[1] = -1; | |
94 | } | |
95 | if (setintr && forked) { | |
96 | if (shudint) | |
97 | signal(SIGINT, SIG_DFL), signal(SIGQUIT, SIG_DFL); | |
98 | signal(SIGTERM, parterm); | |
99 | if (flags & FINT) | |
100 | setintr = 0; | |
101 | } | |
102 | if (func(t, pipein, pipeout)) { | |
103 | if (forked) | |
104 | exitstat(); | |
105 | if (didfds && !(t->t_dflg & FREDO)) | |
106 | donefds(); | |
107 | return; | |
108 | } | |
109 | } | |
110 | } | |
111 | ||
112 | /* | |
113 | * Now, we must make a new process since either the | |
114 | * command is non-builtin, a parenthesized list, | |
115 | * or builtin such as time or nice which really | |
116 | * requires a child. | |
117 | */ | |
118 | if (!forked && (flags & FPAR) == 0) | |
119 | #ifdef VFORK | |
120 | if (t->t_dtyp == TPAR || (flags&FREDO) || | |
121 | eq(t->t_dcom[0], "nice") || eq(t->t_dcom[0], "nohup")) | |
122 | #endif | |
123 | pid = dofork(shudint, shudhup); | |
124 | #ifdef VFORK | |
125 | else { | |
126 | savint = signal(SIGINT, SIG_IGN); | |
127 | ochild = child; osetintr = setintr; | |
128 | ohaderr = haderr; otimflg = timflg; | |
129 | odidfds = didfds; odidcch = didcch; | |
130 | oSHIN = SHIN; oSHOUT = SHOUT; | |
131 | oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; | |
132 | Vsav = Vdp = 0; Vav = 0; | |
133 | isvfork++; | |
134 | pid = vfork(); | |
135 | if (pid < 0) { | |
136 | signal(SIGINT, savint); | |
137 | error("No more processes"); | |
138 | } | |
139 | if (pid == 0) { | |
140 | child++; | |
141 | signal(SIGINT, shudint ? SIG_DFL : savint); | |
142 | if (!shudhup) | |
143 | signal(SIGHUP, SIG_IGN); | |
144 | } else { | |
145 | child = ochild; setintr = osetintr; | |
146 | haderr = ohaderr; timflg = otimflg; | |
147 | didfds = odidfds; didcch = odidcch; | |
148 | SHIN = oSHIN; SHOUT = oSHOUT; | |
149 | SHDIAG = oSHDIAG; OLDSTD = oOLDSTD; | |
150 | xfree(Vsav), Vsav = 0; | |
151 | xfree(Vdp), Vdp = 0; | |
152 | xfree(Vav), Vav = 0; | |
153 | signal(SIGINT, savint); | |
154 | } | |
155 | } | |
156 | #endif | |
157 | if (pid != 0) { | |
158 | /* | |
159 | * The parent path (or nobody does this if | |
160 | * (flags & FPAR), i.e. date in (set;date)) | |
161 | */ | |
162 | if (didfds == 0 && (flags & FPIN)) | |
163 | close(pipein[0]), close(pipein[1]); | |
164 | if (didfds && !(t->t_dflg & FREDO)) | |
165 | donefds(); | |
166 | if (flags & FPRS) | |
167 | printf("%d\n", pid), set("child", putn(pid)); | |
168 | /* | |
169 | * Unless output is piped or command is & | |
170 | * wait for it. | |
171 | */ | |
172 | if (t->t_dtyp == TCOM) | |
173 | cadd(pid, t->t_dcom[0]); | |
174 | else | |
175 | cadd(pid, "()"); | |
176 | if ((flags & (FPOU|FAND)) == 0) | |
177 | pwait(pid); | |
178 | return; | |
179 | } | |
180 | ||
181 | /* | |
182 | * Insure that this (child) shell doesn't muck on | |
183 | */ | |
184 | child++; | |
185 | ||
186 | /* | |
187 | * If havent yet, finally set up the file descriptors. | |
188 | */ | |
189 | doio(t, pipein, pipeout); | |
190 | if (flags & FPOU) | |
191 | close(pipeout[0]), close(pipeout[1]); | |
192 | ||
193 | /* | |
194 | * If mucking with interrupts fix interrupt, quit, | |
195 | * and terminate handling ... in any case set setintr | |
196 | * to 0 if we are not interruptible so that no further | |
197 | * interrupt mucking occurs. | |
198 | */ | |
199 | if (setintr) { | |
200 | if (shudint) { | |
201 | signal(SIGQUIT, SIG_DFL); | |
202 | #ifdef VFORK | |
203 | if (isvfork) | |
204 | signal(SIGINT, vffree); | |
205 | else | |
206 | #endif | |
207 | signal(SIGINT, SIG_DFL); | |
208 | } | |
209 | signal(SIGTERM, parterm); | |
210 | if (flags & FINT) | |
211 | setintr = 0; | |
212 | } | |
213 | ||
214 | /* | |
215 | * For () commands must put new 0,1,2 in FSH* and recurse | |
216 | */ | |
217 | if (t->t_dtyp == TPAR) { | |
218 | t1 = t->t_dspr; | |
219 | t1->t_dflg |= flags & FINT; | |
220 | OLDSTD = dcopy(0, FOLDSTD); | |
221 | SHOUT = dcopy(1, FSHOUT); | |
222 | SHDIAG = dcopy(2, FSHDIAG); | |
223 | close(SHIN), SHIN = -1; | |
224 | didcch = 0, didfds = 0; | |
225 | execute(t1); | |
226 | exitstat(); | |
227 | } | |
228 | if (eq(t->t_dcom[0], "nice")) { | |
229 | /* sigh... | |
230 | nice(20); | |
231 | nice(-10); | |
232 | */ | |
233 | cp = t->t_dcom[1]; | |
234 | if (any(cp[0], "+-")) | |
235 | nice(getn(cp)), lshift(t->t_dcom, 2); | |
236 | else | |
237 | nice(4), lshift(t->t_dcom, 1); | |
238 | t->t_dflg = FPAR | FREDO; | |
239 | execute(t); | |
240 | exitstat(); | |
241 | } | |
242 | if (eq(t->t_dcom[0], "nohup")) { | |
243 | if (setintr == 0) | |
244 | signal(SIGHUP, SIG_IGN); | |
245 | signal(SIGTERM, SIG_IGN); | |
246 | lshift(t->t_dcom, 1); | |
247 | t->t_dflg = FPAR | FREDO; | |
248 | execute(t); | |
249 | exitstat(); | |
250 | } | |
251 | doexec(t); | |
252 | /* no return */ | |
253 | ||
254 | case TFIL: | |
255 | flags = t->t_dflg; | |
256 | t1 = t->t_dcar; | |
257 | t1->t_dflg |= FPOU | (flags & (FPIN|FINT|FPRS|FDIAG)); | |
258 | execute(t1, pipein, pv); | |
259 | t1 = t->t_dcdr; | |
260 | t1->t_dflg |= FPIN | (flags & (FPOU|FINT|FAND|FPRS|FPAR)); | |
261 | execute(t1, pv, pipeout); | |
262 | return; | |
263 | ||
264 | case TLST: | |
265 | flags = t->t_dflg & FINT; | |
266 | if (t1 = t->t_dcar) | |
267 | t1->t_dflg |= flags, execute(t1); | |
268 | if (t1 = t->t_dcdr) | |
269 | t1->t_dflg |= t->t_dflg & (FINT|FPAR), execute(t1); | |
270 | return; | |
271 | ||
272 | case TOR: | |
273 | case TAND: | |
274 | flags = t->t_dflg & FINT; | |
275 | if (t1 = t->t_dcar) { | |
276 | t1->t_dflg |= flags, execute(t1); | |
277 | if ((getn(value("status")) == 0) == (t->t_dtyp == TAND)) | |
278 | return; | |
279 | } | |
280 | if (t1 = t->t_dcdr) | |
281 | t1->t_dflg |= t->t_dflg & (FINT|FPAR), execute(t1); | |
282 | return; | |
283 | } | |
284 | } | |
285 | ||
286 | #ifdef VFORK | |
287 | vffree() | |
288 | { | |
289 | register char **v; | |
290 | ||
291 | if (v = gargv) | |
292 | gargv = 0, xfree(gargv); | |
293 | if (v = pargv) | |
294 | pargv = 0, xfree(pargv); | |
295 | _exit(1); | |
296 | } | |
297 | #endif | |
298 | ||
299 | doio(t, pipein, pipeout) | |
300 | register struct command *t; | |
301 | int *pipein, *pipeout; | |
302 | { | |
303 | register char *cp; | |
304 | register int flags = t->t_dflg; | |
305 | char *dp; | |
306 | ||
307 | if (didfds || (flags & FREDO)) | |
308 | return; | |
309 | if (flags & FHERE) | |
310 | goto skipin; | |
311 | close(0); | |
312 | if (cp = t->t_dlef) { | |
313 | cp = globone(dp = Dfix1(cp)); | |
314 | xfree(dp); | |
315 | xfree(cp); | |
316 | if (open(cp, 0) < 0) | |
317 | Perror(cp); | |
318 | } else if (flags & FPIN) | |
319 | dup(pipein[0]), close(pipein[0]), close(pipein[1]); | |
320 | else if (flags & FINT) | |
321 | close(0), open("/dev/null", 0); | |
322 | else | |
323 | dup(OLDSTD); | |
324 | ||
325 | skipin: | |
326 | close(1); | |
327 | if (cp = t->t_drit) { | |
328 | cp = globone(dp = Dfix1(cp)); | |
329 | xfree(dp); | |
330 | xfree(cp); | |
331 | if ((flags & FCAT) && open(cp, 1) >= 0) | |
332 | lseek(1, 0l, 2); | |
333 | else { | |
334 | if (!(flags & FANY) && adrof("noclobber")) { | |
335 | if (flags & FCAT) | |
336 | Perror(cp); | |
337 | chkclob(cp); | |
338 | } | |
339 | #ifdef V6 | |
340 | if (creat(cp, 0644) < 0) | |
341 | Perror(cp); | |
342 | #else | |
343 | if (creat(cp, 0666) < 0) | |
344 | Perror(cp); | |
345 | #endif | |
346 | } | |
347 | } else | |
348 | dup((flags & FPOU) ? pipeout[1] : SHOUT); | |
349 | ||
350 | close(2); | |
351 | dup((flags & FDIAG) ? 1 : SHDIAG); | |
352 | didfds = 1; | |
353 | } | |
354 | ||
355 | dofork(shudint, shudhup) | |
356 | bool shudint, shudhup; | |
357 | { | |
358 | register int pid, (*savint)(); | |
359 | ||
360 | savint = signal(SIGINT, SIG_IGN); | |
361 | pid = fork(); | |
362 | if (pid < 0) { | |
363 | signal(SIGINT, savint); | |
364 | error("No more processes"); | |
365 | } | |
366 | if (pid == 0) { | |
367 | child++; | |
368 | signal(SIGINT, shudint ? SIG_DFL : savint); | |
369 | if (!shudhup) | |
370 | signal(SIGHUP, SIG_IGN); | |
371 | } else | |
372 | signal(SIGINT, savint); | |
373 | return (pid); | |
374 | } | |
375 | ||
376 | mypipe(pv) | |
377 | register int *pv; | |
378 | { | |
379 | ||
380 | if (pipe(pv) < 0) | |
381 | goto oops; | |
382 | pv[0] = dmove(pv[0], -1); | |
383 | pv[1] = dmove(pv[1], -1); | |
384 | if (pv[0] >= 0 && pv[1] >= 0) | |
385 | return; | |
386 | oops: | |
387 | error("Can't make pipe"); | |
388 | } | |
389 | ||
390 | chkclob(cp) | |
391 | register char *cp; | |
392 | { | |
393 | struct stat stb; | |
394 | ||
395 | if (stat(cp, &stb) < 0) | |
396 | return; | |
397 | if ((stb.st_mode & S_IFMT) == S_IFCHR) | |
398 | return; | |
399 | error("%s: File exists", cp); | |
400 | } |