xref: /netbsd-src/bin/csh/sem.c (revision bbacb4192bd8df457f95dd9b5d9e4b484bae2562)
1*bbacb419Sfox /* $NetBSD: sem.c,v 1.32 2020/02/05 20:06:17 fox Exp $ */
249f0ad86Scgd 
361f28255Scgd /*-
4cee2bad8Smycroft  * Copyright (c) 1980, 1991, 1993
5cee2bad8Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
328ea378c6Schristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
3549f0ad86Scgd static char sccsid[] = "@(#)sem.c	8.1 (Berkeley) 5/31/93";
3649f0ad86Scgd #else
37*bbacb419Sfox __RCSID("$NetBSD: sem.c,v 1.32 2020/02/05 20:06:17 fox Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #include <sys/ioctl.h>
42b771e65bSwiz #include <sys/param.h>
4361f28255Scgd #include <sys/stat.h>
44b771e65bSwiz 
4561f28255Scgd #include <errno.h>
4661f28255Scgd #include <fcntl.h>
4718158540Swiz #include <stdarg.h>
4861f28255Scgd #include <stdlib.h>
4961f28255Scgd #include <string.h>
5061f28255Scgd #include <unistd.h>
51b771e65bSwiz 
5261f28255Scgd #include "csh.h"
5361f28255Scgd #include "extern.h"
54b771e65bSwiz #include "proc.h"
5561f28255Scgd 
565bb1ddccSjoerg __dead static void vffree(int);
57b771e65bSwiz static Char *splicepipe(struct command *t, Char *);
58b771e65bSwiz static void doio(struct command *t, int *, int *);
59b771e65bSwiz static void chkclob(char *);
6061f28255Scgd 
6161f28255Scgd void
execute(struct command * t,int wtty,int * pipein,int * pipeout)6288e26c5aSchristos execute(struct command *t, int wtty, int *pipein, int *pipeout)
6361f28255Scgd {
64b771e65bSwiz     static sigset_t csigset, ocsigset;
65b771e65bSwiz     static int nosigchld = 0, onosigchld = 0;
6688e26c5aSchristos     volatile int wanttty = wtty;
6788e26c5aSchristos     struct biltins * volatile bifunc;
68b771e65bSwiz     int pv[2], pid;
69b3df6303Skleink     sigset_t nsigset;
70*bbacb419Sfox     volatile int forked;
7161f28255Scgd 
72cee2bad8Smycroft     UNREGISTER(forked);
73cee2bad8Smycroft     UNREGISTER(bifunc);
74cee2bad8Smycroft     UNREGISTER(wanttty);
75cee2bad8Smycroft 
76b771e65bSwiz     forked = 0;
77b771e65bSwiz     pid = 0;
78b771e65bSwiz 
7961f28255Scgd     if (t == 0)
8061f28255Scgd 	return;
8161f28255Scgd 
8261f28255Scgd     if (t->t_dflg & F_AMPERSAND)
8361f28255Scgd 	wanttty = 0;
8461f28255Scgd     switch (t->t_dtyp) {
8561f28255Scgd     case NODE_COMMAND:
8661f28255Scgd 	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
8761f28255Scgd 	    (void)Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
8861f28255Scgd 	if ((t->t_dflg & F_REPEAT) == 0)
8961f28255Scgd 	    Dfix(t);		/* $ " ' \ */
9061f28255Scgd 	if (t->t_dcom[0] == 0)
9161f28255Scgd 	    return;
92cdbd74daSmycroft 	/* FALLTHROUGH */
9361f28255Scgd     case NODE_PAREN:
9461f28255Scgd 	if (t->t_dflg & F_PIPEOUT)
9561f28255Scgd 	    mypipe(pipeout);
9661f28255Scgd 	/*
9761f28255Scgd 	 * Must do << early so parent will know where input pointer should be.
9861f28255Scgd 	 * If noexec then this is all we do.
9961f28255Scgd 	 */
10061f28255Scgd 	if (t->t_dflg & F_READ) {
10161f28255Scgd 	    (void)close(0);
10261f28255Scgd 	    heredoc(t->t_dlef);
10361f28255Scgd 	    if (noexec)
10461f28255Scgd 		(void)close(0);
10561f28255Scgd 	}
10661f28255Scgd 
10761f28255Scgd 	set(STRstatus, Strsave(STR0));
10861f28255Scgd 
10961f28255Scgd 	/*
11061f28255Scgd 	 * This mess is the necessary kludge to handle the prefix builtins:
11161f28255Scgd 	 * nice, nohup, time.  These commands can also be used by themselves,
11261f28255Scgd 	 * and this is not handled here. This will also work when loops are
11361f28255Scgd 	 * parsed.
11461f28255Scgd 	 */
11561f28255Scgd 	while (t->t_dtyp == NODE_COMMAND)
116fc32dd30Schristos 	    if (eq(t->t_dcom[0], STRnice)) {
117fc32dd30Schristos 		if (t->t_dcom[1]) {
118fc32dd30Schristos 		    if (strchr("+-", t->t_dcom[1][0])) {
11961f28255Scgd 			if (t->t_dcom[2]) {
12061f28255Scgd 			    setname("nice");
12161f28255Scgd 			    t->t_nice =
12261f28255Scgd 				getn(t->t_dcom[1]);
12361f28255Scgd 			    lshift(t->t_dcom, 2);
12461f28255Scgd 			    t->t_dflg |= F_NICE;
12561f28255Scgd 			}
12661f28255Scgd 			else
12761f28255Scgd 			    break;
128fc32dd30Schristos 		    } else {
12961f28255Scgd 			t->t_nice = 4;
13061f28255Scgd 			lshift(t->t_dcom, 1);
13161f28255Scgd 			t->t_dflg |= F_NICE;
13261f28255Scgd 		    }
133fc32dd30Schristos 		} else
13461f28255Scgd 		    break;
135fc32dd30Schristos 	    } else if (eq(t->t_dcom[0], STRnohup)) {
13661f28255Scgd 		if (t->t_dcom[1]) {
13761f28255Scgd 		    t->t_dflg |= F_NOHUP;
13861f28255Scgd 		    lshift(t->t_dcom, 1);
13961f28255Scgd 		}
14061f28255Scgd 		else
14161f28255Scgd 		    break;
142fc32dd30Schristos 	    } else if (eq(t->t_dcom[0], STRtime)) {
14361f28255Scgd 		if (t->t_dcom[1]) {
14461f28255Scgd 		    t->t_dflg |= F_TIME;
14561f28255Scgd 		    lshift(t->t_dcom, 1);
14661f28255Scgd 		}
14761f28255Scgd 		else
14861f28255Scgd 		    break;
149fc32dd30Schristos 	    } else
15061f28255Scgd 		break;
15161f28255Scgd 
152cee2bad8Smycroft 	/* is it a command */
15361f28255Scgd 	if (t->t_dtyp == NODE_COMMAND) {
15461f28255Scgd 	    /*
15561f28255Scgd 	     * Check if we have a builtin function and remember which one.
15661f28255Scgd 	     */
15761f28255Scgd 	    bifunc = isbfunc(t);
15864aaf6d1Stron  	    if (noexec && bifunc != NULL) {
159cee2bad8Smycroft 		/*
160cee2bad8Smycroft 		 * Continue for builtins that are part of the scripting language
161cee2bad8Smycroft 		 */
162cee2bad8Smycroft 		if (bifunc->bfunct != dobreak   && bifunc->bfunct != docontin &&
163cee2bad8Smycroft 		    bifunc->bfunct != doelse    && bifunc->bfunct != doend    &&
164cee2bad8Smycroft 		    bifunc->bfunct != doforeach && bifunc->bfunct != dogoto   &&
165cee2bad8Smycroft 		    bifunc->bfunct != doif      && bifunc->bfunct != dorepeat &&
166cee2bad8Smycroft 		    bifunc->bfunct != doswbrk   && bifunc->bfunct != doswitch &&
167cee2bad8Smycroft 		    bifunc->bfunct != dowhile   && bifunc->bfunct != dozip)
168cee2bad8Smycroft 		    break;
169cee2bad8Smycroft 	    }
17061f28255Scgd 	}
17161f28255Scgd 	else {			/* not a command */
17261f28255Scgd 	    bifunc = NULL;
173cee2bad8Smycroft 	    if (noexec)
174cee2bad8Smycroft 		break;
17561f28255Scgd 	}
17661f28255Scgd 
17761f28255Scgd 	/*
17861f28255Scgd 	 * We fork only if we are timed, or are not the end of a parenthesized
17961f28255Scgd 	 * list and not a simple builtin function. Simple meaning one that is
18061f28255Scgd 	 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
18161f28255Scgd 	 * fork in some of these cases.
18261f28255Scgd 	 */
18361f28255Scgd 	/*
18461f28255Scgd 	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
18561f28255Scgd 	 * shell not to change dir!
18661f28255Scgd 	 */
18761f28255Scgd 	if (bifunc && (bifunc->bfunct == dochngd ||
18861f28255Scgd 		       bifunc->bfunct == dopushd ||
18961f28255Scgd 		       bifunc->bfunct == dopopd))
19061f28255Scgd 	    t->t_dflg &= ~(F_NICE);
191cee2bad8Smycroft 	if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
19261f28255Scgd 	     (!bifunc || t->t_dflg &
193cee2bad8Smycroft 	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) ||
19461f28255Scgd 	/*
19561f28255Scgd 	 * We have to fork for eval too.
19661f28255Scgd 	 */
197cee2bad8Smycroft 	    (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 &&
198341bd18bSthorpej 	     bifunc->bfunct == doeval)) {
19961f28255Scgd 	    if (t->t_dtyp == NODE_PAREN ||
20061f28255Scgd 		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) {
20161f28255Scgd 		forked++;
20261f28255Scgd 		/*
20361f28255Scgd 		 * We need to block SIGCHLD here, so that if the process does
20461f28255Scgd 		 * not die before we can set the process group
20561f28255Scgd 		 */
20661f28255Scgd 		if (wanttty >= 0 && !nosigchld) {
207b3df6303Skleink 		    sigemptyset(&nsigset);
208b3df6303Skleink 		    (void)sigaddset(&nsigset, SIGCHLD);
209b3df6303Skleink 		    (void)sigprocmask(SIG_BLOCK, &nsigset, &csigset);
21061f28255Scgd 		    nosigchld = 1;
21161f28255Scgd 		}
21261f28255Scgd 
21361f28255Scgd 		pid = pfork(t, wanttty);
21461f28255Scgd 		if (pid == 0 && nosigchld) {
2155924694dSmycroft 		    (void)sigprocmask(SIG_SETMASK, &csigset, NULL);
21661f28255Scgd 		    nosigchld = 0;
21761f28255Scgd 		}
218cee2bad8Smycroft 		else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
219cee2bad8Smycroft 		    backpid = pid;
220cee2bad8Smycroft 
22161f28255Scgd 	    }
22261f28255Scgd 	    else {
22361f28255Scgd 		int ochild, osetintr, ohaderr, odidfds;
224cee2bad8Smycroft 		int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp;
2257b38403cSmycroft 		sigset_t osigset;
22661f28255Scgd 
22761f28255Scgd 		/*
22861f28255Scgd 		 * Prepare for the vfork by saving everything that the child
22961f28255Scgd 		 * corrupts before it exec's. Note that in some signal
23061f28255Scgd 		 * implementations which keep the signal info in user space
23161f28255Scgd 		 * (e.g. Sun's) it will also be necessary to save and restore
2327b38403cSmycroft 		 * the current sigaction's for the signals the child touches
23361f28255Scgd 		 * before it exec's.
23461f28255Scgd 		 */
23561f28255Scgd 		if (wanttty >= 0 && !nosigchld && !noexec) {
236b3df6303Skleink 		    sigemptyset(&nsigset);
237b3df6303Skleink 		    (void)sigaddset(&nsigset, SIGCHLD);
238b3df6303Skleink 		    (void)sigprocmask(SIG_BLOCK, &nsigset, &csigset);
23961f28255Scgd 		    nosigchld = 1;
24061f28255Scgd 		}
241b3df6303Skleink 		sigemptyset(&nsigset);
242b3df6303Skleink 		(void)sigaddset(&nsigset, SIGCHLD);
243b3df6303Skleink 		(void)sigaddset(&nsigset, SIGINT);
244b3df6303Skleink 		(void)sigprocmask(SIG_BLOCK, &nsigset, &osigset);
24561f28255Scgd 		ochild = child;
24661f28255Scgd 		osetintr = setintr;
24761f28255Scgd 		ohaderr = haderr;
24861f28255Scgd 		odidfds = didfds;
24961f28255Scgd 		oSHIN = SHIN;
25061f28255Scgd 		oSHOUT = SHOUT;
251cee2bad8Smycroft 		oSHERR = SHERR;
25261f28255Scgd 		oOLDSTD = OLDSTD;
25361f28255Scgd 		otpgrp = tpgrp;
2547b38403cSmycroft 		ocsigset = csigset;
25561f28255Scgd 		onosigchld = nosigchld;
25661f28255Scgd 		Vsav = Vdp = 0;
25761f28255Scgd 		Vexpath = 0;
25861f28255Scgd 		Vt = 0;
25961f28255Scgd 		pid = vfork();
26061f28255Scgd 
26161f28255Scgd 		if (pid < 0) {
2625924694dSmycroft 		    (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
26361f28255Scgd 		    stderror(ERR_NOPROC);
26461f28255Scgd 		}
26561f28255Scgd 		forked++;
26661f28255Scgd 		if (pid) {	/* parent */
26761f28255Scgd 		    child = ochild;
26861f28255Scgd 		    setintr = osetintr;
26961f28255Scgd 		    haderr = ohaderr;
27061f28255Scgd 		    didfds = odidfds;
27161f28255Scgd 		    SHIN = oSHIN;
27261f28255Scgd 		    SHOUT = oSHOUT;
273cee2bad8Smycroft 		    SHERR = oSHERR;
27461f28255Scgd 		    OLDSTD = oOLDSTD;
27561f28255Scgd 		    tpgrp = otpgrp;
2767b38403cSmycroft 		    csigset = ocsigset;
27761f28255Scgd 		    nosigchld = onosigchld;
27861f28255Scgd 
2791767ce60Schristos 		    free(Vsav);
28061f28255Scgd 		    Vsav = 0;
2811767ce60Schristos 		    free(Vdp);
28261f28255Scgd 		    Vdp = 0;
2831767ce60Schristos 		    free(Vexpath);
28461f28255Scgd 		    Vexpath = 0;
28561f28255Scgd 		    blkfree((Char **)Vt);
28661f28255Scgd 		    Vt = 0;
28761f28255Scgd 		    /* this is from pfork() */
28861f28255Scgd 		    palloc(pid, t);
2895924694dSmycroft 		    (void)sigprocmask(SIG_SETMASK, &osigset, NULL);
29061f28255Scgd 		}
29161f28255Scgd 		else {		/* child */
29261f28255Scgd 		    /* this is from pfork() */
29361f28255Scgd 		    int pgrp;
294b79c2ef2Schristos 		    int ignint = 0;
29561f28255Scgd 
29661f28255Scgd 		    if (nosigchld) {
2975924694dSmycroft 		        (void)sigprocmask(SIG_SETMASK, &csigset, NULL);
29861f28255Scgd 			nosigchld = 0;
29961f28255Scgd 		    }
30061f28255Scgd 
30161f28255Scgd 		    if (setintr)
30261f28255Scgd 			ignint =
30361f28255Scgd 			    (tpgrp == -1 &&
30461f28255Scgd 			     (t->t_dflg & F_NOINTERRUPT))
305cee2bad8Smycroft 			    || (gointr && eq(gointr, STRminus));
30661f28255Scgd 		    pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
30761f28255Scgd 		    child++;
30861f28255Scgd 		    if (setintr) {
30961f28255Scgd 			setintr = 0;
31061f28255Scgd 			if (ignint) {
31161f28255Scgd 			    (void)signal(SIGINT, SIG_IGN);
31261f28255Scgd 			    (void)signal(SIGQUIT, SIG_IGN);
31361f28255Scgd 			}
31461f28255Scgd 			else {
31561f28255Scgd 			    (void)signal(SIGINT, vffree);
31661f28255Scgd 			    (void)signal(SIGQUIT, SIG_DFL);
31761f28255Scgd 			}
31861f28255Scgd 
31961f28255Scgd 			if (wanttty >= 0) {
32061f28255Scgd 			    (void)signal(SIGTSTP, SIG_DFL);
32161f28255Scgd 			    (void)signal(SIGTTIN, SIG_DFL);
32261f28255Scgd 			    (void)signal(SIGTTOU, SIG_DFL);
32361f28255Scgd 			}
32461f28255Scgd 
32561f28255Scgd 			(void)signal(SIGTERM, parterm);
32661f28255Scgd 		    }
32761f28255Scgd 		    else if (tpgrp == -1 &&
32861f28255Scgd 			     (t->t_dflg & F_NOINTERRUPT)) {
32961f28255Scgd 			(void)signal(SIGINT, SIG_IGN);
33061f28255Scgd 			(void)signal(SIGQUIT, SIG_IGN);
33161f28255Scgd 		    }
33261f28255Scgd 
33361f28255Scgd 		    pgetty(wanttty, pgrp);
33461f28255Scgd 		    if (t->t_dflg & F_NOHUP)
33561f28255Scgd 			(void)signal(SIGHUP, SIG_IGN);
33661f28255Scgd 		    if (t->t_dflg & F_NICE)
33761f28255Scgd 			(void)setpriority(PRIO_PROCESS, 0, t->t_nice);
33861f28255Scgd 		}
33961f28255Scgd 
34061f28255Scgd 	    }
341341bd18bSthorpej 	}
34261f28255Scgd 	if (pid != 0) {
34361f28255Scgd 	    /*
34461f28255Scgd 	     * It would be better if we could wait for the whole job when we
34561f28255Scgd 	     * knew the last process had been started.  Pwait, in fact, does
34661f28255Scgd 	     * wait for the whole job anyway, but this test doesn't really
34761f28255Scgd 	     * express our intentions.
34861f28255Scgd 	     */
34961f28255Scgd 	    if (didfds == 0 && t->t_dflg & F_PIPEIN) {
35061f28255Scgd 		(void)close(pipein[0]);
35161f28255Scgd 		(void)close(pipein[1]);
35261f28255Scgd 	    }
35361f28255Scgd 	    if ((t->t_dflg & F_PIPEOUT) == 0) {
35461f28255Scgd 		if (nosigchld) {
3555924694dSmycroft 		    (void)sigprocmask(SIG_SETMASK, &csigset, NULL);
35661f28255Scgd 		    nosigchld = 0;
35761f28255Scgd 		}
35861f28255Scgd 		if ((t->t_dflg & F_AMPERSAND) == 0)
35961f28255Scgd 		    pwait();
36061f28255Scgd 	    }
36161f28255Scgd 	    break;
36261f28255Scgd 	}
36361f28255Scgd 	doio(t, pipein, pipeout);
36461f28255Scgd 	if (t->t_dflg & F_PIPEOUT) {
36561f28255Scgd 	    (void)close(pipeout[0]);
36661f28255Scgd 	    (void)close(pipeout[1]);
36761f28255Scgd 	}
36861f28255Scgd 	/*
36961f28255Scgd 	 * Perform a builtin function. If we are not forked, arrange for
37061f28255Scgd 	 * possible stopping
37161f28255Scgd 	 */
37261f28255Scgd 	if (bifunc) {
37361f28255Scgd 	    func(t, bifunc);
374ee9e50eaSmycroft 	    if (forked)
37561f28255Scgd 		exitstat();
37661f28255Scgd 	    break;
37761f28255Scgd 	}
378ee9e50eaSmycroft 	if (t->t_dtyp != NODE_PAREN)
379cee2bad8Smycroft 	    doexec(NULL, t);
38061f28255Scgd 	/*
38161f28255Scgd 	 * For () commands must put new 0,1,2 in FSH* and recurse
38261f28255Scgd 	 */
383d12e6436Schristos 	(void) ioctl(OLDSTD = dcopy(0, FOLDSTD), FIOCLEX, NULL);
384d12e6436Schristos 	(void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL);
385d12e6436Schristos 	(void) ioctl(SHERR = dcopy(2, FSHERR), FIOCLEX, NULL);
38661f28255Scgd 	(void) close(SHIN);
387d12e6436Schristos 
38861f28255Scgd 	SHIN = -1;
38961f28255Scgd 	didfds = 0;
39061f28255Scgd 	wanttty = -1;
39161f28255Scgd 	t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
39261f28255Scgd 	execute(t->t_dspr, wanttty, NULL, NULL);
39361f28255Scgd 	exitstat();
394cdbd74daSmycroft 	/* NOTREACHED */
39561f28255Scgd     case NODE_PIPE:
39661f28255Scgd 	t->t_dcar->t_dflg |= F_PIPEOUT |
39761f28255Scgd 	    (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
39861f28255Scgd 	execute(t->t_dcar, wanttty, pipein, pv);
39961f28255Scgd 	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
40061f28255Scgd 			(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
40161f28255Scgd 	if (wanttty > 0)
40261f28255Scgd 	    wanttty = 0;	/* got tty already */
40361f28255Scgd 	execute(t->t_dcdr, wanttty, pv, pipeout);
40461f28255Scgd 	break;
40561f28255Scgd     case NODE_LIST:
40661f28255Scgd 	if (t->t_dcar) {
40761f28255Scgd 	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
40861f28255Scgd 	    execute(t->t_dcar, wanttty, NULL, NULL);
40961f28255Scgd 	    /*
41061f28255Scgd 	     * In strange case of A&B make a new job after A
41161f28255Scgd 	     */
41261f28255Scgd 	    if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
41361f28255Scgd 		(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
41461f28255Scgd 		pendjob();
41561f28255Scgd 	}
41661f28255Scgd 	if (t->t_dcdr) {
41761f28255Scgd 	    t->t_dcdr->t_dflg |= t->t_dflg &
41861f28255Scgd 		(F_NOFORK | F_NOINTERRUPT);
41961f28255Scgd 	    execute(t->t_dcdr, wanttty, NULL, NULL);
42061f28255Scgd 	}
42161f28255Scgd 	break;
42261f28255Scgd     case NODE_OR:
42361f28255Scgd     case NODE_AND:
42461f28255Scgd 	if (t->t_dcar) {
42561f28255Scgd 	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
42661f28255Scgd 	    execute(t->t_dcar, wanttty, NULL, NULL);
42761f28255Scgd 	    if ((getn(value(STRstatus)) == 0) !=
42861f28255Scgd 		(t->t_dtyp == NODE_AND))
42961f28255Scgd 		return;
43061f28255Scgd 	}
43161f28255Scgd 	if (t->t_dcdr) {
43261f28255Scgd 	    t->t_dcdr->t_dflg |= t->t_dflg &
43361f28255Scgd 		(F_NOFORK | F_NOINTERRUPT);
43461f28255Scgd 	    execute(t->t_dcdr, wanttty, NULL, NULL);
43561f28255Scgd 	}
43661f28255Scgd 	break;
43761f28255Scgd     }
43861f28255Scgd     /*
43961f28255Scgd      * Fall through for all breaks from switch
44061f28255Scgd      *
44161f28255Scgd      * If there will be no more executions of this command, flush all file
44261f28255Scgd      * descriptors. Places that turn on the F_REPEAT bit are responsible for
44361f28255Scgd      * doing donefds after the last re-execution
44461f28255Scgd      */
44561f28255Scgd     if (didfds && !(t->t_dflg & F_REPEAT))
44661f28255Scgd 	donefds();
44761f28255Scgd }
44861f28255Scgd 
44961f28255Scgd static void
vffree(int i)450b771e65bSwiz vffree(int i)
45161f28255Scgd {
45276adbe2bStls     Char **v;
45361f28255Scgd 
454cee2bad8Smycroft     if ((v = gargv) != NULL) {
45561f28255Scgd 	gargv = 0;
4561767ce60Schristos 	free(v);
45761f28255Scgd     }
458cee2bad8Smycroft     if ((v = pargv) != NULL) {
45961f28255Scgd 	pargv = 0;
4601767ce60Schristos 	free(v);
46161f28255Scgd     }
46261f28255Scgd     _exit(i);
4639dc385beSmycroft     /* NOTREACHED */
46461f28255Scgd }
46561f28255Scgd 
46661f28255Scgd /*
467cee2bad8Smycroft  * Expand and glob the words after an i/o redirection.
468cee2bad8Smycroft  * If more than one word is generated, then update the command vector.
469cee2bad8Smycroft  *
470cee2bad8Smycroft  * This is done differently in all the shells:
471cee2bad8Smycroft  * 1. in the bourne shell and ksh globbing is not performed
472cee2bad8Smycroft  * 2. Bash/csh say ambiguous
473cee2bad8Smycroft  * 3. zsh does i/o to/from all the files
474cee2bad8Smycroft  * 4. itcsh concatenates the words.
475cee2bad8Smycroft  *
476cee2bad8Smycroft  * I don't know what is best to do. I think that Ambiguous is better
477cee2bad8Smycroft  * than restructuring the command vector, because the user can get
478cee2bad8Smycroft  * unexpected results. In any case, the command vector restructuring
479cee2bad8Smycroft  * code is present and the user can choose it by setting noambiguous
480cee2bad8Smycroft  */
481cee2bad8Smycroft static Char *
splicepipe(struct command * t,Char * cp)482b771e65bSwiz splicepipe(struct command *t, Char *cp /* word after < or > */)
483cee2bad8Smycroft {
484cee2bad8Smycroft     Char *blk[2];
485cee2bad8Smycroft 
486cee2bad8Smycroft     if (adrof(STRnoambiguous)) {
487cee2bad8Smycroft 	Char **pv;
488cee2bad8Smycroft 
489cee2bad8Smycroft 	blk[0] = Dfix1(cp); /* expand $ */
490cee2bad8Smycroft 	blk[1] = NULL;
491cee2bad8Smycroft 
492cee2bad8Smycroft 	gflag = 0, tglob(blk);
493cee2bad8Smycroft 	if (gflag) {
494cee2bad8Smycroft 	    pv = globall(blk);
495cee2bad8Smycroft 	    if (pv == NULL) {
496cee2bad8Smycroft 		setname(vis_str(blk[0]));
4971767ce60Schristos 		free(blk[0]);
498cee2bad8Smycroft 		stderror(ERR_NAME | ERR_NOMATCH);
499cdbd74daSmycroft 		/* NOTREACHED */
500cee2bad8Smycroft 	    }
501cee2bad8Smycroft 	    gargv = NULL;
502cee2bad8Smycroft 	    if (pv[1] != NULL) { /* we need to fix the command vector */
503cee2bad8Smycroft 		Char **av = blkspl(t->t_dcom, &pv[1]);
5041767ce60Schristos 		free(t->t_dcom);
505cee2bad8Smycroft 		t->t_dcom = av;
506cee2bad8Smycroft 	    }
5071767ce60Schristos 	    free(blk[0]);
508cee2bad8Smycroft 	    blk[0] = pv[0];
5091767ce60Schristos 	    free(pv);
510cee2bad8Smycroft 	}
511cee2bad8Smycroft     }
512cee2bad8Smycroft     else {
513cee2bad8Smycroft 	blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR);
5141767ce60Schristos 	free(blk[1]);
515cee2bad8Smycroft     }
516cee2bad8Smycroft     return(blk[0]);
517cee2bad8Smycroft }
518cee2bad8Smycroft 
519cee2bad8Smycroft /*
52061f28255Scgd  * Perform io redirection.
52161f28255Scgd  * We may or maynot be forked here.
52261f28255Scgd  */
52361f28255Scgd static void
doio(struct command * t,int * pipein,int * pipeout)524b771e65bSwiz doio(struct command *t, int *pipein, int *pipeout)
52561f28255Scgd {
52676adbe2bStls     Char *cp;
527b771e65bSwiz     int fd, flags;
52861f28255Scgd 
529b771e65bSwiz     flags = t->t_dflg;
53061f28255Scgd     if (didfds || (flags & F_REPEAT))
53161f28255Scgd 	return;
53261f28255Scgd     if ((flags & F_READ) == 0) {/* F_READ already done */
533cee2bad8Smycroft 	if (t->t_dlef) {
53461f28255Scgd 	    char tmp[MAXPATHLEN+1];
53561f28255Scgd 
53661f28255Scgd 	    /*
53761f28255Scgd 	     * so < /dev/std{in,out,err} work
53861f28255Scgd 	     */
53961f28255Scgd 	    (void)dcopy(SHIN, 0);
54061f28255Scgd 	    (void)dcopy(SHOUT, 1);
541cee2bad8Smycroft 	    (void)dcopy(SHERR, 2);
542cee2bad8Smycroft 	    cp = splicepipe(t, t->t_dlef);
543032ed69fSitojun 	    (void)strlcpy(tmp, short2str(cp), sizeof(tmp));
5441767ce60Schristos 	    free(cp);
545cdbd74daSmycroft 	    if ((fd = open(tmp, O_RDONLY)) < 0) {
54661f28255Scgd 		stderror(ERR_SYSTEM, tmp, strerror(errno));
547cdbd74daSmycroft 		/* NOTREACHED */
548cdbd74daSmycroft 	    }
54961f28255Scgd 	    (void)dmove(fd, 0);
55061f28255Scgd 	}
55161f28255Scgd 	else if (flags & F_PIPEIN) {
55261f28255Scgd 	    (void)close(0);
55361f28255Scgd 	    (void)dup(pipein[0]);
55461f28255Scgd 	    (void)close(pipein[0]);
55561f28255Scgd 	    (void)close(pipein[1]);
55661f28255Scgd 	}
55761f28255Scgd 	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
55861f28255Scgd 	    (void)close(0);
55961f28255Scgd 	    (void)open(_PATH_DEVNULL, O_RDONLY);
56061f28255Scgd 	}
56161f28255Scgd 	else {
56261f28255Scgd 	    (void)close(0);
56361f28255Scgd 	    (void)dup(OLDSTD);
56461f28255Scgd 	    (void)ioctl(0, FIONCLEX, NULL);
56561f28255Scgd 	}
56661f28255Scgd     }
567cee2bad8Smycroft     if (t->t_drit) {
56861f28255Scgd 	char    tmp[MAXPATHLEN+1];
56961f28255Scgd 
570cee2bad8Smycroft 	cp = splicepipe(t, t->t_drit);
571032ed69fSitojun 	(void)strlcpy(tmp, short2str(cp), sizeof(tmp));
5721767ce60Schristos 	free(cp);
57361f28255Scgd 	/*
57461f28255Scgd 	 * so > /dev/std{out,err} work
57561f28255Scgd 	 */
57661f28255Scgd 	(void)dcopy(SHOUT, 1);
577cee2bad8Smycroft 	(void)dcopy(SHERR, 2);
57861f28255Scgd 	if ((flags & F_APPEND) &&
57961f28255Scgd #ifdef O_APPEND
58061f28255Scgd 	    (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0);
58161f28255Scgd #else
58261f28255Scgd 	    (fd = open(tmp, O_WRONLY)) >= 0)
5830ab192c9Sjtc 	    (void)lseek(1, (off_t) 0, SEEK_END);
58461f28255Scgd #endif
58561f28255Scgd 	else {
58661f28255Scgd 	    if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
587cdbd74daSmycroft 		if (flags & F_APPEND) {
58861f28255Scgd 		    stderror(ERR_SYSTEM, tmp, strerror(errno));
589cdbd74daSmycroft 		    /* NOTREACHED */
590cdbd74daSmycroft 		}
59161f28255Scgd 		chkclob(tmp);
59261f28255Scgd 	    }
593cdbd74daSmycroft 	    if ((fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
59461f28255Scgd 		stderror(ERR_SYSTEM, tmp, strerror(errno));
595cdbd74daSmycroft 		/* NOTREACHED */
596cdbd74daSmycroft 	    }
59761f28255Scgd 	}
59861f28255Scgd 	(void)dmove(fd, 1);
59961f28255Scgd     }
60061f28255Scgd     else if (flags & F_PIPEOUT) {
60161f28255Scgd 	(void)close(1);
60261f28255Scgd 	(void)dup(pipeout[1]);
60361f28255Scgd     }
60461f28255Scgd     else {
60561f28255Scgd 	(void)close(1);
60661f28255Scgd 	(void)dup(SHOUT);
60761f28255Scgd 	(void)ioctl(1, FIONCLEX, NULL);
60861f28255Scgd     }
60961f28255Scgd 
61061f28255Scgd     (void)close(2);
61161f28255Scgd     if (flags & F_STDERR) {
61261f28255Scgd 	(void)dup(1);
61361f28255Scgd     }
61461f28255Scgd     else {
615cee2bad8Smycroft 	(void)dup(SHERR);
61661f28255Scgd 	(void)ioctl(2, FIONCLEX, NULL);
61761f28255Scgd     }
61861f28255Scgd     didfds = 1;
61961f28255Scgd }
62061f28255Scgd 
62161f28255Scgd void
mypipe(int * pv)622b771e65bSwiz mypipe(int *pv)
62361f28255Scgd {
62461f28255Scgd     if (pipe(pv) < 0)
62561f28255Scgd 	goto oops;
62661f28255Scgd     pv[0] = dmove(pv[0], -1);
62761f28255Scgd     pv[1] = dmove(pv[1], -1);
62861f28255Scgd     if (pv[0] >= 0 && pv[1] >= 0)
62961f28255Scgd 	return;
63061f28255Scgd oops:
63161f28255Scgd     stderror(ERR_PIPE);
632cdbd74daSmycroft     /* NOTREACHED */
63361f28255Scgd }
63461f28255Scgd 
63561f28255Scgd static void
chkclob(char * cp)636b771e65bSwiz chkclob(char *cp)
63761f28255Scgd {
63861f28255Scgd     struct stat stb;
63961f28255Scgd 
64061f28255Scgd     if (stat(cp, &stb) < 0)
64161f28255Scgd 	return;
642cee2bad8Smycroft     if (S_ISCHR(stb.st_mode))
64361f28255Scgd 	return;
64461f28255Scgd     stderror(ERR_EXISTS, cp);
645cdbd74daSmycroft     /* NOTREACHED */
64661f28255Scgd }
647