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