Commit | Line | Data |
---|---|---|
e0cb907a BJ |
1 | static char *sccsid = "@(#)sem.c 4.1 %G%"; |
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 | ||
117 | sighold(SIGCHLD); | |
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) { | |
125 | sigrelse(SIGCHLD); | |
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); | |
140 | sigrelse(SIGCHLD); | |
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; | |
154 | sigsys(SIGCHLD, SIG_DFL); | |
155 | sigsys(SIGINT, ignint ? SIG_IGN : vffree); | |
156 | sigsys(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); | |
157 | if (wanttty >= 0) { | |
158 | sigsys(SIGTSTP, SIG_DFL); | |
159 | sigsys(SIGTTIN, SIG_DFL); | |
160 | sigsys(SIGTTOU, SIG_DFL); | |
161 | } | |
162 | sigsys(SIGTERM, parterm); | |
163 | } else if (tpgrp == -1 && (t->t_dflg&FINT)) { | |
164 | sigsys(SIGINT, SIG_IGN); | |
165 | sigsys(SIGQUIT, SIG_IGN); | |
166 | } | |
167 | if (wanttty > 0) | |
168 | ioctl(FSHTTY, TIOCSPGRP, &pgrp); | |
169 | if (wanttty >= 0 && tpgrp >= 0) | |
170 | setpgrp(0, pgrp); | |
171 | if (tpgrp > 0) | |
172 | tpgrp = 0; | |
173 | if (t->t_dflg & FNOHUP) | |
174 | sigsys(SIGHUP, SIG_IGN); | |
175 | if (t->t_dflg & FNICE) | |
176 | nice(t->t_nice); | |
177 | } | |
178 | ||
179 | } | |
180 | #endif | |
181 | if (pid != 0) { | |
182 | /* | |
183 | * It would be better if we could wait for the | |
184 | * whole job when we knew the last process | |
185 | * had been started. Pwait, in fact, does | |
186 | * wait for the whole job anyway, but this test | |
187 | * doesn't really express our intentions. | |
188 | */ | |
189 | if (didfds==0 && t->t_dflg&FPIN) | |
190 | close(pipein[0]), close(pipein[1]); | |
191 | if ((t->t_dflg & (FPOU|FAND)) == 0) | |
192 | pwait(); | |
193 | break; | |
194 | } | |
195 | doio(t, pipein, pipeout); | |
196 | if (t->t_dflg & FPOU) | |
197 | close(pipeout[0]), close(pipeout[1]); | |
198 | ||
199 | /* | |
200 | * Perform a builtin function. | |
201 | * If we are not forked, arrange for possible stopping | |
202 | */ | |
203 | if (bifunc) { | |
204 | func(t, bifunc); | |
205 | if (forked) | |
206 | exitstat(); | |
207 | break; | |
208 | } | |
209 | if (t->t_dtyp != TPAR) { | |
210 | doexec(t); | |
211 | /*NOTREACHED*/ | |
212 | } | |
213 | /* | |
214 | * For () commands must put new 0,1,2 in FSH* and recurse | |
215 | */ | |
216 | OLDSTD = dcopy(0, FOLDSTD); | |
217 | SHOUT = dcopy(1, FSHOUT); | |
218 | SHDIAG = dcopy(2, FSHDIAG); | |
219 | close(SHIN), SHIN = -1; | |
220 | didcch = 0, didfds = 0; | |
221 | wanttty = -1; | |
222 | t->t_dspr->t_dflg |= t->t_dflg & FINT; | |
223 | execute(t->t_dspr, wanttty); | |
224 | exitstat(); | |
225 | ||
226 | case TFIL: | |
227 | t->t_dcar->t_dflg |= FPOU | | |
228 | (t->t_dflg & (FPIN|FAND|FDIAG|FINT)); | |
229 | execute(t->t_dcar, wanttty, pipein, pv); | |
230 | t->t_dcdr->t_dflg |= FPIN | | |
231 | (t->t_dflg & (FPOU|FAND|FPAR|FINT)); | |
232 | if (wanttty > 0) | |
233 | wanttty = 0; /* got tty already */ | |
234 | execute(t->t_dcdr, wanttty, pv, pipeout); | |
235 | break; | |
236 | ||
237 | case TLST: | |
238 | if (t->t_dcar) { | |
239 | t->t_dcar->t_dflg |= t->t_dflg & FINT; | |
240 | execute(t->t_dcar, wanttty); | |
241 | /* | |
242 | * In strange case of A&B make a new job after A | |
243 | */ | |
244 | if (t->t_dcar->t_dflg&FAND && t->t_dcdr && | |
245 | (t->t_dcdr->t_dflg&FAND) == 0) | |
246 | pendjob(); | |
247 | } | |
248 | if (t->t_dcdr) { | |
249 | t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); | |
250 | execute(t->t_dcdr, wanttty); | |
251 | } | |
252 | break; | |
253 | ||
254 | case TOR: | |
255 | case TAND: | |
256 | if (t->t_dcar) { | |
257 | t->t_dcar->t_dflg |= t->t_dflg & FINT; | |
258 | execute(t->t_dcar, wanttty); | |
259 | if ((getn(value("status")) == 0) != (t->t_dtyp == TAND)) | |
260 | return; | |
261 | } | |
262 | if (t->t_dcdr) { | |
263 | t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); | |
264 | execute(t->t_dcdr, wanttty); | |
265 | } | |
266 | break; | |
267 | } | |
268 | /* | |
269 | * Fall through for all breaks from switch | |
270 | * | |
271 | * If there will be no more executions of this | |
272 | * command, flush all file descriptors. | |
273 | * Places that turn on the FREDO bit are responsible | |
274 | * for doing donefds after the last re-execution | |
275 | */ | |
276 | if (didfds && !(t->t_dflg & FREDO)) | |
277 | donefds(); | |
278 | } | |
279 | ||
280 | #ifdef VFORK | |
281 | vffree() | |
282 | { | |
283 | register char **v; | |
284 | ||
285 | if (v = gargv) | |
286 | gargv = 0, xfree(gargv); | |
287 | if (v = pargv) | |
288 | pargv = 0, xfree(pargv); | |
289 | _exit(1); | |
290 | } | |
291 | #endif | |
292 | ||
293 | /* | |
294 | * Perform io redirection. | |
295 | * We may or maynot be forked here. | |
296 | */ | |
297 | doio(t, pipein, pipeout) | |
298 | register struct command *t; | |
299 | int *pipein, *pipeout; | |
300 | { | |
301 | register char *cp; | |
302 | register int flags = t->t_dflg; | |
303 | ||
304 | if (didfds || (flags & FREDO)) | |
305 | return; | |
306 | if ((flags & FHERE) == 0) { /* FHERE already done */ | |
307 | close(0); | |
308 | if (cp = t->t_dlef) { | |
309 | cp = globone(Dfix1(cp)); | |
310 | xfree(cp); | |
311 | if (open(cp, 0) < 0) | |
312 | Perror(cp); | |
313 | } else if (flags & FPIN) | |
314 | dup(pipein[0]), close(pipein[0]), close(pipein[1]); | |
315 | else if ((flags & FINT) && tpgrp == -1) | |
316 | close(0), open("/dev/null", 0); | |
317 | else | |
318 | dup(OLDSTD); | |
319 | } | |
320 | close(1); | |
321 | if (cp = t->t_drit) { | |
322 | cp = globone(Dfix1(cp)); | |
323 | xfree(cp); | |
324 | if ((flags & FCAT) && open(cp, 1) >= 0) | |
325 | lseek(1, 0l, 2); | |
326 | else { | |
327 | if (!(flags & FANY) && adrof("noclobber")) { | |
328 | if (flags & FCAT) | |
329 | Perror(cp); | |
330 | chkclob(cp); | |
331 | } | |
332 | if (creat(cp, 0666) < 0) | |
333 | Perror(cp); | |
334 | } | |
335 | } else if (flags & FPOU) | |
336 | dup(pipeout[1]); | |
337 | else | |
338 | dup(SHOUT); | |
339 | ||
340 | close(2); | |
341 | dup((flags & FDIAG) ? 1 : SHDIAG); | |
342 | didfds = 1; | |
343 | } | |
344 | ||
345 | mypipe(pv) | |
346 | register int *pv; | |
347 | { | |
348 | ||
349 | if (pipe(pv) < 0) | |
350 | goto oops; | |
351 | pv[0] = dmove(pv[0], -1); | |
352 | pv[1] = dmove(pv[1], -1); | |
353 | if (pv[0] >= 0 && pv[1] >= 0) | |
354 | return; | |
355 | oops: | |
356 | error("Can't make pipe"); | |
357 | } | |
358 | ||
359 | chkclob(cp) | |
360 | register char *cp; | |
361 | { | |
362 | struct stat stb; | |
363 | ||
364 | if (stat(cp, &stb) < 0) | |
365 | return; | |
366 | if ((stb.st_mode & S_IFMT) == S_IFCHR) | |
367 | return; | |
368 | error("%s: File exists", cp); | |
369 | } |