Commit | Line | Data |
---|---|---|
ecc449eb KB |
1 | /*- |
2 | * Copyright (c) 1980, 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.redist.c% | |
b79f4fa9 DF |
6 | */ |
7 | ||
35371dec | 8 | #ifndef lint |
6e37afca | 9 | static char sccsid[] = "@(#)sem.c 5.12 (Berkeley) %G%"; |
ecc449eb | 10 | #endif /* not lint */ |
e0cb907a BJ |
11 | |
12 | #include "sh.h" | |
6e37afca | 13 | #include "sh.dir.h" |
e0cb907a | 14 | #include "sh.proc.h" |
6e37afca KB |
15 | |
16 | #ifdef VFORK | |
17 | static void vffree(); | |
18 | ||
19 | #endif | |
20 | static void doio(); | |
21 | static void chkclob(); | |
e0cb907a BJ |
22 | |
23 | /* | |
24 | * C shell | |
25 | */ | |
e0cb907a | 26 | /*VARARGS 1*/ |
6e37afca | 27 | void |
e0cb907a | 28 | execute(t, wanttty, pipein, pipeout) |
6e37afca KB |
29 | register struct command *t; |
30 | int wanttty, *pipein, *pipeout; | |
e0cb907a | 31 | { |
6e37afca KB |
32 | bool forked = 0; |
33 | struct biltins *bifunc; | |
34 | int pid = 0; | |
35 | int pv[2]; | |
e0cb907a | 36 | |
6e37afca | 37 | static sigmask_t csigmask; |
e0cb907a | 38 | |
6e37afca KB |
39 | #ifdef VFORK |
40 | static sigmask_t ocsigmask; | |
e0cb907a | 41 | |
6e37afca KB |
42 | #endif /* VFORK */ |
43 | static int onosigchld = 0; | |
44 | static int nosigchld = 0; | |
e0cb907a | 45 | |
6e37afca KB |
46 | if (t == 0) |
47 | return; | |
48 | ||
49 | if (t->t_dflg & F_AMPERSAND) | |
50 | wanttty = 0; | |
51 | switch (t->t_dtyp) { | |
52 | ||
53 | case NODE_COMMAND: | |
54 | if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) | |
55 | (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); | |
56 | if ((t->t_dflg & F_REPEAT) == 0) | |
57 | Dfix(t); /* $ " ' \ */ | |
58 | if (t->t_dcom[0] == 0) | |
59 | return; | |
60 | /* fall into... */ | |
61 | ||
62 | case NODE_PAREN: | |
63 | if (t->t_dflg & F_PIPEOUT) | |
64 | mypipe(pipeout); | |
65 | /* | |
66 | * Must do << early so parent will know where input pointer should be. | |
67 | * If noexec then this is all we do. | |
68 | */ | |
69 | if (t->t_dflg & F_READ) { | |
70 | (void) close(0); | |
71 | heredoc(t->t_dlef); | |
72 | if (noexec) | |
73 | (void) close(0); | |
74 | } | |
75 | if (noexec) | |
76 | break; | |
77 | ||
78 | set(STRstatus, Strsave(STR0)); | |
79 | ||
80 | /* | |
81 | * This mess is the necessary kludge to handle the prefix builtins: | |
82 | * nice, nohup, time. These commands can also be used by themselves, | |
83 | * and this is not handled here. This will also work when loops are | |
84 | * parsed. | |
85 | */ | |
86 | while (t->t_dtyp == NODE_COMMAND) | |
87 | if (eq(t->t_dcom[0], STRnice)) | |
88 | if (t->t_dcom[1]) | |
89 | if (strchr("+-", t->t_dcom[1][0])) | |
90 | if (t->t_dcom[2]) { | |
91 | setname("nice"); | |
92 | t->t_nice = | |
93 | getn(t->t_dcom[1]); | |
94 | lshift(t->t_dcom, 2); | |
95 | t->t_dflg |= F_NICE; | |
85443bfb | 96 | } |
6e37afca KB |
97 | else |
98 | break; | |
e0cb907a | 99 | else { |
6e37afca KB |
100 | t->t_nice = 4; |
101 | lshift(t->t_dcom, 1); | |
102 | t->t_dflg |= F_NICE; | |
d33af40e | 103 | } |
6e37afca KB |
104 | else |
105 | break; | |
106 | else if (eq(t->t_dcom[0], STRnohup)) | |
107 | if (t->t_dcom[1]) { | |
108 | t->t_dflg |= F_NOHUP; | |
109 | lshift(t->t_dcom, 1); | |
e0cb907a | 110 | } |
6e37afca KB |
111 | else |
112 | break; | |
113 | else if (eq(t->t_dcom[0], STRtime)) | |
114 | if (t->t_dcom[1]) { | |
115 | t->t_dflg |= F_TIME; | |
116 | lshift(t->t_dcom, 1); | |
35371dec | 117 | } |
6e37afca KB |
118 | else |
119 | break; | |
120 | else | |
121 | break; | |
122 | ||
123 | /* is t a command */ | |
124 | if (t->t_dtyp == NODE_COMMAND) { | |
125 | /* | |
126 | * Check if we have a builtin function and remember which one. | |
127 | */ | |
128 | bifunc = isbfunc(t); | |
129 | } | |
130 | else { /* not a command */ | |
131 | bifunc = (struct biltins *) 0; | |
132 | } | |
e0cb907a | 133 | |
6e37afca KB |
134 | /* |
135 | * We fork only if we are timed, or are not the end of a parenthesized | |
136 | * list and not a simple builtin function. Simple meaning one that is | |
137 | * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not | |
138 | * fork in some of these cases. | |
139 | */ | |
140 | /* | |
141 | * Prevent forking cd, pushd, popd, chdir cause this will cause the | |
142 | * shell not to change dir! | |
143 | */ | |
144 | if (bifunc && (bifunc->bfunct == dochngd || | |
145 | bifunc->bfunct == dopushd || | |
146 | bifunc->bfunct == dopopd)) | |
147 | t->t_dflg &= ~(F_NICE); | |
148 | if (((t->t_dflg & F_TIME) || (t->t_dflg & F_NOFORK) == 0 && | |
149 | (!bifunc || t->t_dflg & | |
150 | (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP))) || | |
151 | /* | |
152 | * We have to fork for eval too. | |
153 | */ | |
154 | (bifunc && (t->t_dflg & F_PIPEIN) != 0 && | |
155 | bifunc->bfunct == doeval)) | |
156 | #ifdef VFORK | |
157 | if (t->t_dtyp == NODE_PAREN || | |
158 | t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) | |
159 | #endif | |
160 | { | |
161 | forked++; | |
e0cb907a | 162 | /* |
6e37afca KB |
163 | * We need to block SIGCHLD here, so that if the process does |
164 | * not die before we can set the process group | |
e0cb907a | 165 | */ |
6e37afca KB |
166 | if (wanttty >= 0 && !nosigchld) { |
167 | csigmask = sigblock(sigmask(SIGCHLD)); | |
168 | nosigchld = 1; | |
e0cb907a | 169 | } |
6e37afca KB |
170 | |
171 | pid = pfork(t, wanttty); | |
172 | if (pid == 0 && nosigchld) { | |
173 | (void) sigsetmask(csigmask); | |
174 | nosigchld = 0; | |
e0cb907a | 175 | } |
6e37afca KB |
176 | } |
177 | ||
178 | #ifdef VFORK | |
179 | else { | |
180 | int ochild, osetintr, ohaderr, odidfds; | |
181 | int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; | |
182 | sigmask_t omask; | |
183 | ||
e0cb907a | 184 | /* |
6e37afca KB |
185 | * Prepare for the vfork by saving everything that the child |
186 | * corrupts before it exec's. Note that in some signal | |
187 | * implementations which keep the signal info in user space | |
188 | * (e.g. Sun's) it will also be necessary to save and restore | |
189 | * the current sigvec's for the signals the child touches | |
190 | * before it exec's. | |
e0cb907a | 191 | */ |
6e37afca KB |
192 | if (wanttty >= 0 && !nosigchld && !noexec) { |
193 | csigmask = sigblock(sigmask(SIGCHLD)); | |
194 | nosigchld = 1; | |
195 | } | |
196 | omask = sigblock(sigmask(SIGCHLD) | sigmask(SIGINT)); | |
197 | ochild = child; | |
198 | osetintr = setintr; | |
199 | ohaderr = haderr; | |
200 | odidfds = didfds; | |
201 | oSHIN = SHIN; | |
202 | oSHOUT = SHOUT; | |
203 | oSHDIAG = SHDIAG; | |
204 | oOLDSTD = OLDSTD; | |
205 | otpgrp = tpgrp; | |
206 | ocsigmask = csigmask; | |
207 | onosigchld = nosigchld; | |
208 | Vsav = Vdp = 0; | |
209 | Vexpath = 0; | |
210 | Vt = 0; | |
211 | pid = vfork(); | |
e0cb907a | 212 | |
6e37afca KB |
213 | if (pid < 0) { |
214 | (void) sigsetmask(omask); | |
215 | stderror(ERR_NOPROC); | |
e0cb907a | 216 | } |
6e37afca KB |
217 | forked++; |
218 | if (pid) { /* parent */ | |
219 | child = ochild; | |
220 | setintr = osetintr; | |
221 | haderr = ohaderr; | |
222 | didfds = odidfds; | |
223 | SHIN = oSHIN; | |
224 | SHOUT = oSHOUT; | |
225 | SHDIAG = oSHDIAG; | |
226 | OLDSTD = oOLDSTD; | |
227 | tpgrp = otpgrp; | |
228 | csigmask = ocsigmask; | |
229 | nosigchld = onosigchld; | |
230 | ||
231 | xfree((ptr_t) Vsav); | |
232 | Vsav = 0; | |
233 | xfree((ptr_t) Vdp); | |
234 | Vdp = 0; | |
235 | xfree((ptr_t) Vexpath); | |
236 | Vexpath = 0; | |
237 | blkfree((Char **) Vt); | |
238 | Vt = 0; | |
239 | /* this is from pfork() */ | |
240 | palloc(pid, t); | |
241 | (void) sigsetmask(omask); | |
e0cb907a | 242 | } |
6e37afca KB |
243 | else { /* child */ |
244 | /* this is from pfork() */ | |
245 | int pgrp; | |
246 | bool ignint = 0; | |
247 | ||
248 | if (nosigchld) { | |
249 | (void) sigsetmask(csigmask); | |
250 | nosigchld = 0; | |
251 | } | |
252 | ||
253 | if (setintr) | |
254 | ignint = | |
255 | (tpgrp == -1 && | |
256 | (t->t_dflg & F_NOINTERRUPT)) | |
257 | || gointr && eq(gointr, STRminus); | |
258 | pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); | |
259 | child++; | |
260 | if (setintr) { | |
261 | setintr = 0; | |
262 | if (ignint) { | |
263 | (void) signal(SIGINT, SIG_IGN); | |
264 | (void) signal(SIGQUIT, SIG_IGN); | |
265 | } | |
266 | else { | |
267 | (void) signal(SIGINT, vffree); | |
268 | (void) signal(SIGQUIT, SIG_DFL); | |
269 | } | |
e0cb907a | 270 | |
6e37afca KB |
271 | if (wanttty >= 0) { |
272 | (void) signal(SIGTSTP, SIG_DFL); | |
273 | (void) signal(SIGTTIN, SIG_DFL); | |
274 | (void) signal(SIGTTOU, SIG_DFL); | |
275 | } | |
276 | ||
277 | (void) signal(SIGTERM, parterm); | |
278 | } | |
279 | else if (tpgrp == -1 && | |
280 | (t->t_dflg & F_NOINTERRUPT)) { | |
281 | (void) signal(SIGINT, SIG_IGN); | |
282 | (void) signal(SIGQUIT, SIG_IGN); | |
283 | } | |
284 | ||
285 | pgetty(wanttty, pgrp); | |
286 | if (t->t_dflg & F_NOHUP) | |
287 | (void) signal(SIGHUP, SIG_IGN); | |
288 | if (t->t_dflg & F_NICE) | |
289 | (void) setpriority(PRIO_PROCESS, 0, t->t_nice); | |
e0cb907a | 290 | } |
6e37afca KB |
291 | |
292 | } | |
293 | #endif /* VFORK */ | |
294 | if (pid != 0) { | |
295 | /* | |
296 | * It would be better if we could wait for the whole job when we | |
297 | * knew the last process had been started. Pwait, in fact, does | |
298 | * wait for the whole job anyway, but this test doesn't really | |
299 | * express our intentions. | |
300 | */ | |
301 | if (didfds == 0 && t->t_dflg & F_PIPEIN) { | |
302 | (void) close(pipein[0]); | |
303 | (void) close(pipein[1]); | |
304 | } | |
305 | if ((t->t_dflg & F_PIPEOUT) == 0) { | |
306 | if (nosigchld) { | |
307 | (void) sigsetmask(csigmask); | |
308 | nosigchld = 0; | |
e0cb907a | 309 | } |
6e37afca KB |
310 | if ((t->t_dflg & F_AMPERSAND) == 0) |
311 | pwait(); | |
312 | } | |
313 | break; | |
314 | } | |
315 | doio(t, pipein, pipeout); | |
316 | if (t->t_dflg & F_PIPEOUT) { | |
317 | (void) close(pipeout[0]); | |
318 | (void) close(pipeout[1]); | |
319 | } | |
320 | /* | |
321 | * Perform a builtin function. If we are not forked, arrange for | |
322 | * possible stopping | |
323 | */ | |
324 | if (bifunc) { | |
325 | func(t, bifunc); | |
326 | if (forked) | |
327 | exitstat(); | |
328 | break; | |
329 | } | |
330 | if (t->t_dtyp != NODE_PAREN) { | |
331 | doexec(t); | |
332 | /* NOTREACHED */ | |
e0cb907a BJ |
333 | } |
334 | /* | |
6e37afca | 335 | * For () commands must put new 0,1,2 in FSH* and recurse |
e0cb907a | 336 | */ |
6e37afca KB |
337 | OLDSTD = dcopy(0, FOLDSTD); |
338 | SHOUT = dcopy(1, FSHOUT); | |
339 | SHDIAG = dcopy(2, FSHDIAG); | |
340 | (void) close(SHIN); | |
341 | SHIN = -1; | |
342 | didfds = 0; | |
343 | wanttty = -1; | |
344 | t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; | |
345 | execute(t->t_dspr, wanttty, NULL, NULL); | |
346 | exitstat(); | |
347 | ||
348 | case NODE_PIPE: | |
349 | t->t_dcar->t_dflg |= F_PIPEOUT | | |
350 | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT)); | |
351 | execute(t->t_dcar, wanttty, pipein, pv); | |
352 | t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & | |
353 | (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT)); | |
354 | if (wanttty > 0) | |
355 | wanttty = 0; /* got tty already */ | |
356 | execute(t->t_dcdr, wanttty, pv, pipeout); | |
357 | break; | |
358 | ||
359 | case NODE_LIST: | |
360 | if (t->t_dcar) { | |
361 | t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; | |
362 | execute(t->t_dcar, wanttty, NULL, NULL); | |
363 | /* | |
364 | * In strange case of A&B make a new job after A | |
365 | */ | |
366 | if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && | |
367 | (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) | |
368 | pendjob(); | |
369 | } | |
370 | if (t->t_dcdr) { | |
371 | t->t_dcdr->t_dflg |= t->t_dflg & | |
372 | (F_NOFORK | F_NOINTERRUPT); | |
373 | execute(t->t_dcdr, wanttty, NULL, NULL); | |
374 | } | |
375 | break; | |
376 | ||
377 | case NODE_OR: | |
378 | case NODE_AND: | |
379 | if (t->t_dcar) { | |
380 | t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; | |
381 | execute(t->t_dcar, wanttty, NULL, NULL); | |
382 | if ((getn(value(STRstatus)) == 0) != | |
383 | (t->t_dtyp == NODE_AND)) | |
384 | return; | |
385 | } | |
386 | if (t->t_dcdr) { | |
387 | t->t_dcdr->t_dflg |= t->t_dflg & | |
388 | (F_NOFORK | F_NOINTERRUPT); | |
389 | execute(t->t_dcdr, wanttty, NULL, NULL); | |
390 | } | |
391 | break; | |
392 | } | |
393 | /* | |
394 | * Fall through for all breaks from switch | |
395 | * | |
396 | * If there will be no more executions of this command, flush all file | |
397 | * descriptors. Places that turn on the F_REPEAT bit are responsible for | |
398 | * doing donefds after the last re-execution | |
399 | */ | |
400 | if (didfds && !(t->t_dflg & F_REPEAT)) | |
401 | donefds(); | |
e0cb907a BJ |
402 | } |
403 | ||
404 | #ifdef VFORK | |
6e37afca | 405 | static void |
e0cb907a BJ |
406 | vffree() |
407 | { | |
6e37afca | 408 | register Char **v; |
e0cb907a | 409 | |
6e37afca KB |
410 | if (v = gargv) { |
411 | gargv = 0; | |
412 | xfree((ptr_t) v); | |
413 | } | |
414 | if (v = pargv) { | |
415 | pargv = 0; | |
416 | xfree((ptr_t) v); | |
417 | } | |
418 | _exit(1); | |
e0cb907a | 419 | } |
6e37afca | 420 | |
e0cb907a BJ |
421 | #endif |
422 | ||
423 | /* | |
424 | * Perform io redirection. | |
425 | * We may or maynot be forked here. | |
426 | */ | |
6e37afca | 427 | static void |
e0cb907a | 428 | doio(t, pipein, pipeout) |
6e37afca KB |
429 | register struct command *t; |
430 | int *pipein, *pipeout; | |
e0cb907a | 431 | { |
6e37afca KB |
432 | register int fd; |
433 | register Char *cp; | |
434 | register int flags = t->t_dflg; | |
e0cb907a | 435 | |
6e37afca KB |
436 | if (didfds || (flags & F_REPEAT)) |
437 | return; | |
438 | if ((flags & F_READ) == 0) {/* F_READ already done */ | |
439 | if (cp = t->t_dlef) { | |
440 | char tmp[MAXPATHLEN]; | |
441 | ||
442 | /* | |
443 | * so < /dev/std{in,out,err} work | |
444 | */ | |
445 | (void) dcopy(SHIN, 0); | |
446 | (void) dcopy(SHOUT, 1); | |
447 | (void) dcopy(SHDIAG, 2); | |
448 | cp = globone(Dfix1(cp), G_IGNORE); | |
449 | (void) strncpy(tmp, short2str(cp), MAXPATHLEN); | |
450 | tmp[MAXPATHLEN - 1] = '\0'; | |
451 | xfree((ptr_t) cp); | |
452 | if ((fd = open(tmp, O_RDONLY)) < 0) | |
453 | stderror(ERR_SYSTEM, tmp, strerror(errno)); | |
454 | (void) dmove(fd, 0); | |
455 | } | |
456 | else if (flags & F_PIPEIN) { | |
457 | (void) close(0); | |
458 | (void) dup(pipein[0]); | |
459 | (void) close(pipein[0]); | |
460 | (void) close(pipein[1]); | |
461 | } | |
462 | else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { | |
463 | (void) close(0); | |
464 | (void) open(_PATH_DEVNULL, O_RDONLY); | |
e0cb907a | 465 | } |
6e37afca KB |
466 | else { |
467 | (void) close(0); | |
468 | (void) dup(OLDSTD); | |
469 | (void) ioctl(0, FIONCLEX, (char *) 0); | |
470 | } | |
471 | } | |
472 | if (cp = t->t_drit) { | |
473 | Char tmp[MAXPATHLEN]; | |
474 | ||
475 | cp = globone(Dfix1(cp), G_IGNORE); | |
476 | (void) Strncpy(tmp, cp, MAXPATHLEN); | |
477 | tmp[MAXPATHLEN - 1] = '\0'; | |
478 | xfree((ptr_t) cp); | |
479 | /* | |
480 | * so > /dev/std{out,err} work | |
481 | */ | |
482 | (void) dcopy(SHOUT, 1); | |
483 | (void) dcopy(SHDIAG, 2); | |
484 | if ((flags & F_APPEND) && | |
485 | #ifdef O_APPEND | |
486 | (fd = open(short2str(tmp), O_WRONLY | O_APPEND)) >= 0); | |
487 | #else | |
488 | (fd = open(short2str(tmp), O_WRONLY)) >= 0) | |
489 | (void) lseek(1, (off_t) 0, L_XTND); | |
490 | #endif | |
491 | else { | |
492 | if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) { | |
493 | if (flags & F_APPEND) | |
494 | stderror(ERR_SYSTEM, short2str(tmp), strerror(errno)); | |
495 | chkclob(tmp); | |
496 | } | |
497 | if ((fd = creat(short2str(tmp), 0666)) < 0) | |
498 | stderror(ERR_SYSTEM, short2str(tmp), strerror(errno)); | |
499 | } | |
500 | (void) dmove(fd, 1); | |
501 | } | |
502 | else if (flags & F_PIPEOUT) { | |
35371dec | 503 | (void) close(1); |
6e37afca KB |
504 | (void) dup(pipeout[1]); |
505 | } | |
506 | else { | |
507 | (void) close(1); | |
508 | (void) dup(SHOUT); | |
509 | (void) ioctl(1, FIONCLEX, (char *) 0); | |
510 | } | |
511 | ||
512 | (void) close(2); | |
513 | if (flags & F_STDERR) { | |
514 | (void) dup(1); | |
515 | } | |
516 | else { | |
517 | (void) dup(SHDIAG); | |
518 | (void) ioctl(2, FIONCLEX, (char *) 0); | |
519 | } | |
520 | didfds = 1; | |
e0cb907a BJ |
521 | } |
522 | ||
6e37afca | 523 | void |
e0cb907a | 524 | mypipe(pv) |
6e37afca | 525 | register int *pv; |
e0cb907a BJ |
526 | { |
527 | ||
6e37afca KB |
528 | if (pipe(pv) < 0) |
529 | goto oops; | |
530 | pv[0] = dmove(pv[0], -1); | |
531 | pv[1] = dmove(pv[1], -1); | |
532 | if (pv[0] >= 0 && pv[1] >= 0) | |
533 | return; | |
e0cb907a | 534 | oops: |
6e37afca | 535 | stderror(ERR_PIPE); |
e0cb907a BJ |
536 | } |
537 | ||
6e37afca | 538 | static void |
e0cb907a | 539 | chkclob(cp) |
6e37afca | 540 | register Char *cp; |
e0cb907a | 541 | { |
6e37afca KB |
542 | struct stat stb; |
543 | char *ptr; | |
e0cb907a | 544 | |
6e37afca KB |
545 | if (stat(ptr = short2str(cp), &stb) < 0) |
546 | return; | |
547 | if ((stb.st_mode & S_IFMT) == S_IFCHR) | |
548 | return; | |
549 | stderror(ERR_EXISTS, ptr); | |
e0cb907a | 550 | } |