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