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