prototype typo fixes
[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
0aec749d 9static 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
17static void vffree __P((int));
18static void doio __P((struct command *t, int *, int *));
19static void chkclob __P((Char *));
e0cb907a 20
6e37afca 21void
e0cb907a 22execute(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 389static void
0aec749d
CZ
390vffree(i)
391int 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 410static void
e0cb907a 411doio(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 506void
e0cb907a 507mypipe(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 517oops:
6e37afca 518 stderror(ERR_PIPE);
e0cb907a
BJ
519}
520
6e37afca 521static void
e0cb907a 522chkclob(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}