Commit | Line | Data |
---|---|---|
2f2a0649 | 1 | static char *sccsid = "@(#)sem.c 4.3 %G%"; |
e0cb907a BJ |
2 | |
3 | #include "sh.h" | |
4 | #include "sh.proc.h" | |
5 | #include <sys/ioctl.h> | |
6 | ||
7 | /* | |
8 | * C shell | |
9 | */ | |
10 | ||
11 | /*VARARGS 1*/ | |
12 | execute(t, wanttty, pipein, pipeout) | |
13 | register struct command *t; | |
14 | int wanttty, *pipein, *pipeout; | |
15 | { | |
16 | bool forked = 0; | |
17 | struct biltins *bifunc; | |
18 | int pid = 0; | |
19 | int pv[2]; | |
20 | ||
21 | if (t == 0) | |
22 | return; | |
23 | if ((t->t_dflg & FAND) && wanttty > 0) | |
24 | wanttty = 0; | |
25 | switch (t->t_dtyp) { | |
26 | ||
27 | case TCOM: | |
28 | if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE) | |
29 | strcpy(t->t_dcom[0], t->t_dcom[0] + 1); | |
30 | if ((t->t_dflg & FREDO) == 0) | |
31 | Dfix(t); /* $ " ' \ */ | |
32 | if (t->t_dcom[0] == 0) | |
33 | return; | |
34 | /* fall into... */ | |
35 | ||
36 | case TPAR: | |
37 | if (t->t_dflg & FPOU) | |
38 | mypipe(pipeout); | |
39 | /* | |
40 | * Must do << early so parent will know | |
41 | * where input pointer should be. | |
42 | * If noexec then this is all we do. | |
43 | */ | |
44 | if (t->t_dflg & FHERE) { | |
45 | close(0); | |
46 | heredoc(t->t_dlef); | |
47 | if (noexec) | |
48 | close(0); | |
49 | } | |
50 | if (noexec) | |
51 | break; | |
52 | ||
53 | set("status", "0"); | |
54 | ||
55 | /* | |
56 | * This mess is the necessary kludge to handle the prefix | |
57 | * builtins: nice, nohup, time. These commands can also | |
58 | * be used by themselves, and this is not handled here. | |
59 | * This will also work when loops are parsed. | |
60 | */ | |
61 | while (t->t_dtyp == TCOM) | |
62 | if (eq(t->t_dcom[0], "nice")) | |
63 | if (t->t_dcom[1]) | |
64 | if (any(t->t_dcom[1][0], "+-")) | |
65 | if (t->t_dcom[2]) { | |
66 | setname("nice"); | |
67 | t->t_nice = getn(t->t_dcom[1]); | |
68 | lshift(t->t_dcom, 2); | |
69 | t->t_dflg |= FNICE; | |
70 | } else | |
71 | break; | |
72 | else { | |
73 | t->t_nice = 4; | |
74 | lshift(t->t_dcom, 1); | |
75 | t->t_dflg |= FNICE; | |
76 | } | |
77 | else | |
78 | break; | |
79 | else if (eq(t->t_dcom[0], "nohup")) | |
80 | if (t->t_dcom[1]) { | |
81 | t->t_dflg |= FNOHUP; | |
82 | lshift(t->t_dcom, 1); | |
83 | } else | |
84 | break; | |
85 | else if (eq(t->t_dcom[0], "time")) | |
86 | if (t->t_dcom[1]) { | |
87 | t->t_dflg |= FTIME; | |
88 | lshift(t->t_dcom, 1); | |
89 | } else | |
90 | break; | |
91 | else | |
92 | break; | |
93 | /* | |
94 | * Check if we have a builtin function and remember which one. | |
95 | */ | |
96 | bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0; | |
97 | ||
98 | /* | |
99 | * We fork only if we are timed, or are not the end of | |
100 | * a parenthesized list and not a simple builtin function. | |
101 | * Simple meaning one that is not pipedout, niced, nohupped, | |
102 | * or &'d. | |
103 | * It would be nice(?) to not fork in some of these cases. | |
104 | */ | |
105 | if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 && | |
106 | (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP)))) | |
107 | #ifdef VFORK | |
108 | if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc) | |
109 | #endif | |
110 | { forked++; pid = pfork(t, wanttty); } | |
111 | #ifdef VFORK | |
112 | else { | |
113 | int vffree(); | |
114 | int ochild, osetintr, ohaderr, odidfds, odidcch; | |
115 | int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; | |
116 | ||
2f2a0649 | 117 | sighold(SIGCHLD); |
e0cb907a BJ |
118 | ochild = child; osetintr = setintr; |
119 | ohaderr = haderr; odidfds = didfds; odidcch = didcch; | |
120 | oSHIN = SHIN; oSHOUT = SHOUT; | |
121 | oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; | |
122 | Vsav = Vdp = 0; Vav = 0; | |
123 | pid = vfork(); | |
124 | if (pid < 0) { | |
2f2a0649 | 125 | sigrelse(SIGCHLD); |
e0cb907a BJ |
126 | error("No more processes"); |
127 | } | |
128 | forked++; | |
129 | if (pid) { | |
130 | child = ochild; setintr = osetintr; | |
131 | haderr = ohaderr; didfds = odidfds; | |
132 | didcch = odidcch; SHIN = oSHIN; | |
133 | SHOUT = oSHOUT; SHDIAG = oSHDIAG; | |
134 | OLDSTD = oOLDSTD; tpgrp = otpgrp; | |
135 | xfree(Vsav); Vsav = 0; | |
136 | xfree(Vdp); Vdp = 0; | |
137 | xfree(Vav); Vav = 0; | |
138 | /* this is from pfork() */ | |
139 | palloc(pid, t); | |
2f2a0649 | 140 | sigrelse(SIGCHLD); |
e0cb907a BJ |
141 | } else { |
142 | /* this is from pfork() */ | |
143 | int pgrp; | |
144 | bool ignint = 0; | |
145 | ||
146 | if (setintr) | |
147 | ignint = | |
148 | (tpgrp == -1 && (t->t_dflg&FINT)) | |
149 | || gointr && eq(gointr, "-"); | |
150 | pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); | |
151 | child++; | |
152 | if (setintr) { | |
153 | setintr = 0; | |
ec1a81af | 154 | #ifdef notdef |
2f2a0649 | 155 | sigsys(SIGCHLD, SIG_DFL); |
ec1a81af | 156 | #endif |
2f2a0649 | 157 | sigsys(SIGINT, |
ec1a81af | 158 | ignint ? SIG_IGN : vffree); |
2f2a0649 | 159 | sigsys(SIGQUIT, |
ec1a81af | 160 | ignint ? SIG_IGN : SIG_DFL); |
e0cb907a | 161 | if (wanttty >= 0) { |
2f2a0649 SL |
162 | sigsys(SIGTSTP, SIG_DFL); |
163 | sigsys(SIGTTIN, SIG_DFL); | |
164 | sigsys(SIGTTOU, SIG_DFL); | |
e0cb907a | 165 | } |
2f2a0649 | 166 | sigsys(SIGTERM, parterm); |
e0cb907a | 167 | } else if (tpgrp == -1 && (t->t_dflg&FINT)) { |
2f2a0649 SL |
168 | sigsys(SIGINT, SIG_IGN); |
169 | sigsys(SIGQUIT, SIG_IGN); | |
e0cb907a BJ |
170 | } |
171 | if (wanttty > 0) | |
172 | ioctl(FSHTTY, TIOCSPGRP, &pgrp); | |
173 | if (wanttty >= 0 && tpgrp >= 0) | |
174 | setpgrp(0, pgrp); | |
175 | if (tpgrp > 0) | |
176 | tpgrp = 0; | |
177 | if (t->t_dflg & FNOHUP) | |
2f2a0649 | 178 | sigsys(SIGHUP, SIG_IGN); |
e0cb907a BJ |
179 | if (t->t_dflg & FNICE) |
180 | nice(t->t_nice); | |
181 | } | |
182 | ||
183 | } | |
184 | #endif | |
185 | if (pid != 0) { | |
186 | /* | |
187 | * It would be better if we could wait for the | |
188 | * whole job when we knew the last process | |
189 | * had been started. Pwait, in fact, does | |
190 | * wait for the whole job anyway, but this test | |
191 | * doesn't really express our intentions. | |
192 | */ | |
193 | if (didfds==0 && t->t_dflg&FPIN) | |
194 | close(pipein[0]), close(pipein[1]); | |
195 | if ((t->t_dflg & (FPOU|FAND)) == 0) | |
196 | pwait(); | |
197 | break; | |
198 | } | |
199 | doio(t, pipein, pipeout); | |
200 | if (t->t_dflg & FPOU) | |
201 | close(pipeout[0]), close(pipeout[1]); | |
202 | ||
203 | /* | |
204 | * Perform a builtin function. | |
205 | * If we are not forked, arrange for possible stopping | |
206 | */ | |
207 | if (bifunc) { | |
208 | func(t, bifunc); | |
209 | if (forked) | |
210 | exitstat(); | |
211 | break; | |
212 | } | |
213 | if (t->t_dtyp != TPAR) { | |
214 | doexec(t); | |
215 | /*NOTREACHED*/ | |
216 | } | |
217 | /* | |
218 | * For () commands must put new 0,1,2 in FSH* and recurse | |
219 | */ | |
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 | wanttty = -1; | |
226 | t->t_dspr->t_dflg |= t->t_dflg & FINT; | |
227 | execute(t->t_dspr, wanttty); | |
228 | exitstat(); | |
229 | ||
230 | case TFIL: | |
231 | t->t_dcar->t_dflg |= FPOU | | |
232 | (t->t_dflg & (FPIN|FAND|FDIAG|FINT)); | |
233 | execute(t->t_dcar, wanttty, pipein, pv); | |
234 | t->t_dcdr->t_dflg |= FPIN | | |
235 | (t->t_dflg & (FPOU|FAND|FPAR|FINT)); | |
236 | if (wanttty > 0) | |
237 | wanttty = 0; /* got tty already */ | |
238 | execute(t->t_dcdr, wanttty, pv, pipeout); | |
239 | break; | |
240 | ||
241 | case TLST: | |
242 | if (t->t_dcar) { | |
243 | t->t_dcar->t_dflg |= t->t_dflg & FINT; | |
244 | execute(t->t_dcar, wanttty); | |
245 | /* | |
246 | * In strange case of A&B make a new job after A | |
247 | */ | |
248 | if (t->t_dcar->t_dflg&FAND && t->t_dcdr && | |
249 | (t->t_dcdr->t_dflg&FAND) == 0) | |
250 | pendjob(); | |
251 | } | |
252 | if (t->t_dcdr) { | |
253 | t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); | |
254 | execute(t->t_dcdr, wanttty); | |
255 | } | |
256 | break; | |
257 | ||
258 | case TOR: | |
259 | case TAND: | |
260 | if (t->t_dcar) { | |
261 | t->t_dcar->t_dflg |= t->t_dflg & FINT; | |
262 | execute(t->t_dcar, wanttty); | |
263 | if ((getn(value("status")) == 0) != (t->t_dtyp == TAND)) | |
264 | return; | |
265 | } | |
266 | if (t->t_dcdr) { | |
267 | t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); | |
268 | execute(t->t_dcdr, wanttty); | |
269 | } | |
270 | break; | |
271 | } | |
272 | /* | |
273 | * Fall through for all breaks from switch | |
274 | * | |
275 | * If there will be no more executions of this | |
276 | * command, flush all file descriptors. | |
277 | * Places that turn on the FREDO bit are responsible | |
278 | * for doing donefds after the last re-execution | |
279 | */ | |
280 | if (didfds && !(t->t_dflg & FREDO)) | |
281 | donefds(); | |
282 | } | |
283 | ||
284 | #ifdef VFORK | |
285 | vffree() | |
286 | { | |
287 | register char **v; | |
288 | ||
289 | if (v = gargv) | |
290 | gargv = 0, xfree(gargv); | |
291 | if (v = pargv) | |
292 | pargv = 0, xfree(pargv); | |
293 | _exit(1); | |
294 | } | |
295 | #endif | |
296 | ||
297 | /* | |
298 | * Perform io redirection. | |
299 | * We may or maynot be forked here. | |
300 | */ | |
301 | doio(t, pipein, pipeout) | |
302 | register struct command *t; | |
303 | int *pipein, *pipeout; | |
304 | { | |
305 | register char *cp; | |
306 | register int flags = t->t_dflg; | |
307 | ||
308 | if (didfds || (flags & FREDO)) | |
309 | return; | |
310 | if ((flags & FHERE) == 0) { /* FHERE already done */ | |
311 | close(0); | |
312 | if (cp = t->t_dlef) { | |
313 | cp = globone(Dfix1(cp)); | |
314 | xfree(cp); | |
315 | if (open(cp, 0) < 0) | |
316 | Perror(cp); | |
317 | } else if (flags & FPIN) | |
318 | dup(pipein[0]), close(pipein[0]), close(pipein[1]); | |
319 | else if ((flags & FINT) && tpgrp == -1) | |
320 | close(0), open("/dev/null", 0); | |
321 | else | |
322 | dup(OLDSTD); | |
323 | } | |
324 | close(1); | |
325 | if (cp = t->t_drit) { | |
326 | cp = globone(Dfix1(cp)); | |
327 | xfree(cp); | |
328 | if ((flags & FCAT) && open(cp, 1) >= 0) | |
329 | lseek(1, 0l, 2); | |
330 | else { | |
331 | if (!(flags & FANY) && adrof("noclobber")) { | |
332 | if (flags & FCAT) | |
333 | Perror(cp); | |
334 | chkclob(cp); | |
335 | } | |
336 | if (creat(cp, 0666) < 0) | |
337 | Perror(cp); | |
338 | } | |
339 | } else if (flags & FPOU) | |
340 | dup(pipeout[1]); | |
341 | else | |
342 | dup(SHOUT); | |
343 | ||
344 | close(2); | |
345 | dup((flags & FDIAG) ? 1 : SHDIAG); | |
346 | didfds = 1; | |
347 | } | |
348 | ||
349 | mypipe(pv) | |
350 | register int *pv; | |
351 | { | |
352 | ||
353 | if (pipe(pv) < 0) | |
354 | goto oops; | |
355 | pv[0] = dmove(pv[0], -1); | |
356 | pv[1] = dmove(pv[1], -1); | |
357 | if (pv[0] >= 0 && pv[1] >= 0) | |
358 | return; | |
359 | oops: | |
360 | error("Can't make pipe"); | |
361 | } | |
362 | ||
363 | chkclob(cp) | |
364 | register char *cp; | |
365 | { | |
366 | struct stat stb; | |
367 | ||
368 | if (stat(cp, &stb) < 0) | |
369 | return; | |
370 | if ((stb.st_mode & S_IFMT) == S_IFCHR) | |
371 | return; | |
372 | error("%s: File exists", cp); | |
373 | } |