date and time created 91/06/04 16:56:10 by christos
[unix-history] / usr / src / bin / csh / sem.c
CommitLineData
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 9static 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
17static void vffree();
18
19#endif
20static void doio();
21static void chkclob();
e0cb907a
BJ
22
23/*
24 * C shell
25 */
e0cb907a 26/*VARARGS 1*/
6e37afca 27void
e0cb907a 28execute(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 405static void
e0cb907a
BJ
406vffree()
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 427static void
e0cb907a 428doio(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 523void
e0cb907a 524mypipe(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 534oops:
6e37afca 535 stderror(ERR_PIPE);
e0cb907a
BJ
536}
537
6e37afca 538static void
e0cb907a 539chkclob(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}