xref: /original-bsd/bin/csh/sem.c (revision c1549ed3)
1*c1549ed3Sdist /*
2*c1549ed3Sdist  * Copyright (c) 1980 Regents of the University of California.
3*c1549ed3Sdist  * All rights reserved.  The Berkeley software License Agreement
4*c1549ed3Sdist  * specifies the terms and conditions for redistribution.
5*c1549ed3Sdist  */
6*c1549ed3Sdist 
743fabe3fSedward #ifndef lint
8*c1549ed3Sdist static char sccsid[] = "@(#)sem.c	5.1 (Berkeley) 06/04/85";
9*c1549ed3Sdist #endif not lint
1013082428Sbill 
1113082428Sbill #include "sh.h"
1213082428Sbill #include "sh.proc.h"
1313082428Sbill #include <sys/ioctl.h>
1413082428Sbill 
1513082428Sbill /*
1613082428Sbill  * C shell
1713082428Sbill  */
1813082428Sbill 
1913082428Sbill /*VARARGS 1*/
2013082428Sbill execute(t, wanttty, pipein, pipeout)
2113082428Sbill 	register struct command *t;
2213082428Sbill 	int wanttty, *pipein, *pipeout;
2313082428Sbill {
2413082428Sbill 	bool forked = 0;
2513082428Sbill 	struct biltins *bifunc;
2613082428Sbill 	int pid = 0;
2713082428Sbill 	int pv[2];
2813082428Sbill 
2913082428Sbill 	if (t == 0)
3013082428Sbill 		return;
3113082428Sbill 	if ((t->t_dflg & FAND) && wanttty > 0)
3213082428Sbill 		wanttty = 0;
3313082428Sbill 	switch (t->t_dtyp) {
3413082428Sbill 
3513082428Sbill 	case TCOM:
3613082428Sbill 		if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE)
3743fabe3fSedward 			(void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
3813082428Sbill 		if ((t->t_dflg & FREDO) == 0)
3913082428Sbill 			Dfix(t);		/* $ " ' \ */
4013082428Sbill 		if (t->t_dcom[0] == 0)
4113082428Sbill 			return;
4213082428Sbill 		/* fall into... */
4313082428Sbill 
4413082428Sbill 	case TPAR:
4513082428Sbill 		if (t->t_dflg & FPOU)
4613082428Sbill 			mypipe(pipeout);
4713082428Sbill 		/*
4813082428Sbill 		 * Must do << early so parent will know
4913082428Sbill 		 * where input pointer should be.
5013082428Sbill 		 * If noexec then this is all we do.
5113082428Sbill 		 */
5213082428Sbill 		if (t->t_dflg & FHERE) {
5343fabe3fSedward 			(void) close(0);
5413082428Sbill 			heredoc(t->t_dlef);
5513082428Sbill 			if (noexec)
5643fabe3fSedward 				(void) close(0);
5713082428Sbill 		}
5813082428Sbill 		if (noexec)
5913082428Sbill 			break;
6013082428Sbill 
6113082428Sbill 		set("status", "0");
6213082428Sbill 
6313082428Sbill 		/*
6413082428Sbill 		 * This mess is the necessary kludge to handle the prefix
6513082428Sbill 		 * builtins: nice, nohup, time.  These commands can also
6613082428Sbill 		 * be used by themselves, and this is not handled here.
6713082428Sbill 		 * This will also work when loops are parsed.
6813082428Sbill 		 */
6913082428Sbill 		while (t->t_dtyp == TCOM)
7013082428Sbill 			if (eq(t->t_dcom[0], "nice"))
7113082428Sbill 				if (t->t_dcom[1])
7213082428Sbill 					if (any(t->t_dcom[1][0], "+-"))
7313082428Sbill 						if (t->t_dcom[2]) {
7413082428Sbill 							setname("nice");
7513082428Sbill 							t->t_nice = getn(t->t_dcom[1]);
7613082428Sbill 							lshift(t->t_dcom, 2);
7713082428Sbill 							t->t_dflg |= FNICE;
7813082428Sbill 						} else
7913082428Sbill 							break;
8013082428Sbill 					else {
8113082428Sbill 						t->t_nice = 4;
8213082428Sbill 						lshift(t->t_dcom, 1);
8313082428Sbill 						t->t_dflg |= FNICE;
8413082428Sbill 					}
8513082428Sbill 				else
8613082428Sbill 					break;
8713082428Sbill 			else if (eq(t->t_dcom[0], "nohup"))
8813082428Sbill 				if (t->t_dcom[1]) {
8913082428Sbill 					t->t_dflg |= FNOHUP;
9013082428Sbill 					lshift(t->t_dcom, 1);
9113082428Sbill 				} else
9213082428Sbill 					break;
9313082428Sbill 			else if (eq(t->t_dcom[0], "time"))
9413082428Sbill 				if (t->t_dcom[1]) {
9513082428Sbill 					t->t_dflg |= FTIME;
9613082428Sbill 					lshift(t->t_dcom, 1);
9713082428Sbill 				} else
9813082428Sbill 					break;
9913082428Sbill 			else
10013082428Sbill 				break;
10113082428Sbill 		/*
10213082428Sbill 		 * Check if we have a builtin function and remember which one.
10313082428Sbill 		 */
10413082428Sbill 		bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0;
10513082428Sbill 
10613082428Sbill 		/*
10713082428Sbill 		 * We fork only if we are timed, or are not the end of
10813082428Sbill 		 * a parenthesized list and not a simple builtin function.
10913082428Sbill 		 * Simple meaning one that is not pipedout, niced, nohupped,
11013082428Sbill 		 * or &'d.
11113082428Sbill 		 * It would be nice(?) to not fork in some of these cases.
11213082428Sbill 		 */
11313082428Sbill 		if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 &&
11413082428Sbill 		     (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP))))
11513082428Sbill #ifdef VFORK
11613082428Sbill 		    if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc)
11713082428Sbill #endif
11813082428Sbill 			{ forked++; pid = pfork(t, wanttty); }
11913082428Sbill #ifdef VFORK
12013082428Sbill 		    else {
12113082428Sbill 			int vffree();
12243fabe3fSedward 			int ochild, osetintr, ohaderr, odidfds;
12313082428Sbill 			int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
1241e9806efSralph 			int omask;
12513082428Sbill 
1261e9806efSralph 			omask = sigblock(sigmask(SIGCHLD));
12713082428Sbill 			ochild = child; osetintr = setintr;
12843fabe3fSedward 			ohaderr = haderr; odidfds = didfds;
12913082428Sbill 			oSHIN = SHIN; oSHOUT = SHOUT;
13013082428Sbill 			oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp;
13113082428Sbill 			Vsav = Vdp = 0; Vav = 0;
13213082428Sbill 			pid = vfork();
13313082428Sbill 			if (pid < 0) {
13443fabe3fSedward 				(void) sigsetmask(omask);
13513082428Sbill 				error("No more processes");
13613082428Sbill 			}
13713082428Sbill 			forked++;
13813082428Sbill 			if (pid) {
13913082428Sbill 				child = ochild; setintr = osetintr;
14013082428Sbill 				haderr = ohaderr; didfds = odidfds;
14143fabe3fSedward 				SHIN = oSHIN;
14213082428Sbill 				SHOUT = oSHOUT; SHDIAG = oSHDIAG;
14313082428Sbill 				OLDSTD = oOLDSTD; tpgrp = otpgrp;
14413082428Sbill 				xfree(Vsav); Vsav = 0;
14513082428Sbill 				xfree(Vdp); Vdp = 0;
14643fabe3fSedward 				xfree((char *)Vav); Vav = 0;
14713082428Sbill 				/* this is from pfork() */
14813082428Sbill 				palloc(pid, t);
14943fabe3fSedward 				(void) sigsetmask(omask);
15013082428Sbill 			} else {
15113082428Sbill 				/* this is from pfork() */
15213082428Sbill 				int pgrp;
15313082428Sbill 				bool ignint = 0;
15413082428Sbill 
15513082428Sbill 				if (setintr)
15613082428Sbill 					ignint =
15713082428Sbill 					    (tpgrp == -1 && (t->t_dflg&FINT))
15813082428Sbill 					    || gointr && eq(gointr, "-");
15913082428Sbill 				pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
16013082428Sbill 				child++;
16113082428Sbill 				if (setintr) {
16213082428Sbill 					setintr = 0;
1632c8ae23aSsam #ifdef notdef
16443fabe3fSedward 					(void) signal(SIGCHLD, SIG_DFL);
1652c8ae23aSsam #endif
16643fabe3fSedward 					(void) signal(SIGINT, ignint ?
1671e9806efSralph 						SIG_IGN : vffree);
16843fabe3fSedward 					(void) signal(SIGQUIT, ignint ?
1691e9806efSralph 						SIG_IGN : SIG_DFL);
17013082428Sbill 					if (wanttty >= 0) {
17143fabe3fSedward 						(void) signal(SIGTSTP, SIG_DFL);
17243fabe3fSedward 						(void) signal(SIGTTIN, SIG_DFL);
17343fabe3fSedward 						(void) signal(SIGTTOU, SIG_DFL);
17413082428Sbill 					}
17543fabe3fSedward 					(void) signal(SIGTERM, parterm);
17613082428Sbill 				} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
17743fabe3fSedward 					(void) signal(SIGINT, SIG_IGN);
17843fabe3fSedward 					(void) signal(SIGQUIT, SIG_IGN);
17913082428Sbill 				}
18013082428Sbill 				if (wanttty > 0)
18143fabe3fSedward 					(void) ioctl(FSHTTY, TIOCSPGRP,
18243fabe3fSedward 						(char *)&pgrp);
18313082428Sbill 				if (wanttty >= 0 && tpgrp >= 0)
18443fabe3fSedward 					(void) setpgrp(0, pgrp);
18513082428Sbill 				if (tpgrp > 0)
18613082428Sbill 					tpgrp = 0;
18713082428Sbill 				if (t->t_dflg & FNOHUP)
18843fabe3fSedward 					(void) signal(SIGHUP, SIG_IGN);
18913082428Sbill 				if (t->t_dflg & FNICE)
19043fabe3fSedward 					(void) setpriority(PRIO_PROCESS,
19143fabe3fSedward 						0, t->t_nice);
19213082428Sbill 			}
19313082428Sbill 
19413082428Sbill 		    }
19513082428Sbill #endif
19613082428Sbill 		if (pid != 0) {
19713082428Sbill 			/*
19813082428Sbill 			 * It would be better if we could wait for the
19913082428Sbill 			 * whole job when we knew the last process
20013082428Sbill 			 * had been started.  Pwait, in fact, does
20113082428Sbill 			 * wait for the whole job anyway, but this test
20213082428Sbill 			 * doesn't really express our intentions.
20313082428Sbill 			 */
20443fabe3fSedward 			if (didfds==0 && t->t_dflg&FPIN) {
20543fabe3fSedward 				(void) close(pipein[0]);
20643fabe3fSedward 				(void) close(pipein[1]);
20743fabe3fSedward 			}
20813082428Sbill 			if ((t->t_dflg & (FPOU|FAND)) == 0)
20913082428Sbill 				pwait();
21013082428Sbill 			break;
21113082428Sbill 		}
21213082428Sbill 		doio(t, pipein, pipeout);
21343fabe3fSedward 		if (t->t_dflg & FPOU) {
21443fabe3fSedward 			(void) close(pipeout[0]);
21543fabe3fSedward 			(void) close(pipeout[1]);
21643fabe3fSedward 		}
21713082428Sbill 
21813082428Sbill 		/*
21913082428Sbill 		 * Perform a builtin function.
22013082428Sbill 		 * If we are not forked, arrange for possible stopping
22113082428Sbill 		 */
22213082428Sbill 		if (bifunc) {
22313082428Sbill 			func(t, bifunc);
22413082428Sbill 			if (forked)
22513082428Sbill 				exitstat();
22613082428Sbill 			break;
22713082428Sbill 		}
22813082428Sbill 		if (t->t_dtyp != TPAR) {
22913082428Sbill 			doexec(t);
23013082428Sbill 			/*NOTREACHED*/
23113082428Sbill 		}
23213082428Sbill 		/*
23313082428Sbill 		 * For () commands must put new 0,1,2 in FSH* and recurse
23413082428Sbill 		 */
23513082428Sbill 		OLDSTD = dcopy(0, FOLDSTD);
23613082428Sbill 		SHOUT = dcopy(1, FSHOUT);
23713082428Sbill 		SHDIAG = dcopy(2, FSHDIAG);
23843fabe3fSedward 		(void) close(SHIN);
23943fabe3fSedward 		SHIN = -1;
24043fabe3fSedward 		didfds = 0;
24113082428Sbill 		wanttty = -1;
24213082428Sbill 		t->t_dspr->t_dflg |= t->t_dflg & FINT;
24313082428Sbill 		execute(t->t_dspr, wanttty);
24413082428Sbill 		exitstat();
24513082428Sbill 
24613082428Sbill 	case TFIL:
24713082428Sbill 		t->t_dcar->t_dflg |= FPOU |
24813082428Sbill 		    (t->t_dflg & (FPIN|FAND|FDIAG|FINT));
24913082428Sbill 		execute(t->t_dcar, wanttty, pipein, pv);
25013082428Sbill 		t->t_dcdr->t_dflg |= FPIN |
25113082428Sbill 		    (t->t_dflg & (FPOU|FAND|FPAR|FINT));
25213082428Sbill 		if (wanttty > 0)
25313082428Sbill 			wanttty = 0;		/* got tty already */
25413082428Sbill 		execute(t->t_dcdr, wanttty, pv, pipeout);
25513082428Sbill 		break;
25613082428Sbill 
25713082428Sbill 	case TLST:
25813082428Sbill 		if (t->t_dcar) {
25913082428Sbill 			t->t_dcar->t_dflg |= t->t_dflg & FINT;
26013082428Sbill 			execute(t->t_dcar, wanttty);
26113082428Sbill 			/*
26213082428Sbill 			 * In strange case of A&B make a new job after A
26313082428Sbill 			 */
26413082428Sbill 			if (t->t_dcar->t_dflg&FAND && t->t_dcdr &&
26513082428Sbill 			    (t->t_dcdr->t_dflg&FAND) == 0)
26613082428Sbill 				pendjob();
26713082428Sbill 		}
26813082428Sbill 		if (t->t_dcdr) {
26913082428Sbill 			t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
27013082428Sbill 			execute(t->t_dcdr, wanttty);
27113082428Sbill 		}
27213082428Sbill 		break;
27313082428Sbill 
27413082428Sbill 	case TOR:
27513082428Sbill 	case TAND:
27613082428Sbill 		if (t->t_dcar) {
27713082428Sbill 			t->t_dcar->t_dflg |= t->t_dflg & FINT;
27813082428Sbill 			execute(t->t_dcar, wanttty);
27913082428Sbill 			if ((getn(value("status")) == 0) != (t->t_dtyp == TAND))
28013082428Sbill 				return;
28113082428Sbill 		}
28213082428Sbill 		if (t->t_dcdr) {
28313082428Sbill 			t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
28413082428Sbill 			execute(t->t_dcdr, wanttty);
28513082428Sbill 		}
28613082428Sbill 		break;
28713082428Sbill 	}
28813082428Sbill 	/*
28913082428Sbill 	 * Fall through for all breaks from switch
29013082428Sbill 	 *
29113082428Sbill 	 * If there will be no more executions of this
29213082428Sbill 	 * command, flush all file descriptors.
29313082428Sbill 	 * Places that turn on the FREDO bit are responsible
29413082428Sbill 	 * for doing donefds after the last re-execution
29513082428Sbill 	 */
29613082428Sbill 	if (didfds && !(t->t_dflg & FREDO))
29713082428Sbill 		donefds();
29813082428Sbill }
29913082428Sbill 
30013082428Sbill #ifdef VFORK
30113082428Sbill vffree()
30213082428Sbill {
30313082428Sbill 	register char **v;
30413082428Sbill 
30513082428Sbill 	if (v = gargv)
30643fabe3fSedward 		gargv = 0, xfree((char *)v);
30713082428Sbill 	if (v = pargv)
30843fabe3fSedward 		pargv = 0, xfree((char *)v);
30913082428Sbill 	_exit(1);
31013082428Sbill }
31113082428Sbill #endif
31213082428Sbill 
31313082428Sbill /*
31413082428Sbill  * Perform io redirection.
31513082428Sbill  * We may or maynot be forked here.
31613082428Sbill  */
31713082428Sbill doio(t, pipein, pipeout)
31813082428Sbill 	register struct command *t;
31913082428Sbill 	int *pipein, *pipeout;
32013082428Sbill {
32113082428Sbill 	register char *cp;
32213082428Sbill 	register int flags = t->t_dflg;
32313082428Sbill 
32413082428Sbill 	if (didfds || (flags & FREDO))
32513082428Sbill 		return;
32613082428Sbill 	if ((flags & FHERE) == 0) {	/* FHERE already done */
32743fabe3fSedward 		(void) close(0);
32813082428Sbill 		if (cp = t->t_dlef) {
32913082428Sbill 			cp = globone(Dfix1(cp));
33013082428Sbill 			xfree(cp);
33113082428Sbill 			if (open(cp, 0) < 0)
33213082428Sbill 				Perror(cp);
33343fabe3fSedward 		} else if (flags & FPIN) {
33443fabe3fSedward 			(void) dup(pipein[0]);
33543fabe3fSedward 			(void) close(pipein[0]);
33643fabe3fSedward 			(void) close(pipein[1]);
33743fabe3fSedward 		} else if ((flags & FINT) && tpgrp == -1) {
33843fabe3fSedward 			(void) close(0);
33943fabe3fSedward 			(void) open("/dev/null", 0);
34043fabe3fSedward 		} else
341cde959b4Sedward 			(void) dup(OLDSTD);
34213082428Sbill 	}
34343fabe3fSedward 	(void) close(1);
34413082428Sbill 	if (cp = t->t_drit) {
34513082428Sbill 		cp = globone(Dfix1(cp));
34613082428Sbill 		xfree(cp);
34713082428Sbill 		if ((flags & FCAT) && open(cp, 1) >= 0)
34843fabe3fSedward 			(void) lseek(1, (off_t)0, 2);
34913082428Sbill 		else {
35013082428Sbill 			if (!(flags & FANY) && adrof("noclobber")) {
35113082428Sbill 				if (flags & FCAT)
35213082428Sbill 					Perror(cp);
35313082428Sbill 				chkclob(cp);
35413082428Sbill 			}
35513082428Sbill 			if (creat(cp, 0666) < 0)
35613082428Sbill 				Perror(cp);
35713082428Sbill 		}
35813082428Sbill 	} else if (flags & FPOU)
35943fabe3fSedward 		(void) dup(pipeout[1]);
36013082428Sbill 	else
361cde959b4Sedward 		(void) dup(SHOUT);
36213082428Sbill 
36343fabe3fSedward 	(void) close(2);
36443fabe3fSedward 	if (flags & FDIAG)
36543fabe3fSedward 		(void) dup(1);
36643fabe3fSedward 	else
367cde959b4Sedward 		(void) dup(SHDIAG);
36813082428Sbill 	didfds = 1;
36913082428Sbill }
37013082428Sbill 
37113082428Sbill mypipe(pv)
37213082428Sbill 	register int *pv;
37313082428Sbill {
37413082428Sbill 
37513082428Sbill 	if (pipe(pv) < 0)
37613082428Sbill 		goto oops;
37713082428Sbill 	pv[0] = dmove(pv[0], -1);
37813082428Sbill 	pv[1] = dmove(pv[1], -1);
37913082428Sbill 	if (pv[0] >= 0 && pv[1] >= 0)
38013082428Sbill 		return;
38113082428Sbill oops:
38213082428Sbill 	error("Can't make pipe");
38313082428Sbill }
38413082428Sbill 
38513082428Sbill chkclob(cp)
38613082428Sbill 	register char *cp;
38713082428Sbill {
38813082428Sbill 	struct stat stb;
38913082428Sbill 
39013082428Sbill 	if (stat(cp, &stb) < 0)
39113082428Sbill 		return;
39213082428Sbill 	if ((stb.st_mode & S_IFMT) == S_IFCHR)
39313082428Sbill 		return;
39413082428Sbill 	error("%s: File exists", cp);
39513082428Sbill }
396