sh.sem.c revision 83098
183098Smp/* $Header: /src/pub/tcsh/sh.sem.c,v 3.53 2001/08/06 23:52:03 christos Exp $ */
259243Sobrien/*
359243Sobrien * sh.sem.c: I/O redirections and job forking. A touchy issue!
459243Sobrien *	     Most stuff with builtins is incorrect
559243Sobrien */
659243Sobrien/*-
759243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
859243Sobrien * All rights reserved.
959243Sobrien *
1059243Sobrien * Redistribution and use in source and binary forms, with or without
1159243Sobrien * modification, are permitted provided that the following conditions
1259243Sobrien * are met:
1359243Sobrien * 1. Redistributions of source code must retain the above copyright
1459243Sobrien *    notice, this list of conditions and the following disclaimer.
1559243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1659243Sobrien *    notice, this list of conditions and the following disclaimer in the
1759243Sobrien *    documentation and/or other materials provided with the distribution.
1859243Sobrien * 3. All advertising materials mentioning features or use of this software
1959243Sobrien *    must display the following acknowledgement:
2059243Sobrien *	This product includes software developed by the University of
2159243Sobrien *	California, Berkeley and its contributors.
2259243Sobrien * 4. Neither the name of the University nor the names of its contributors
2359243Sobrien *    may be used to endorse or promote products derived from this software
2459243Sobrien *    without specific prior written permission.
2559243Sobrien *
2659243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2759243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2859243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2959243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3059243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3159243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3259243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3359243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3459243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3559243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3659243Sobrien * SUCH DAMAGE.
3759243Sobrien */
3859243Sobrien#include "sh.h"
3959243Sobrien
4083098SmpRCSID("$Id: sh.sem.c,v 3.53 2001/08/06 23:52:03 christos Exp $")
4159243Sobrien
4259243Sobrien#include "tc.h"
4359243Sobrien#include "tw.h"
4469408Sache#ifdef WINNT_NATIVE
4559243Sobrien#include "nt.const.h"
4669408Sache#endif /*WINNT_NATIVE*/
4759243Sobrien
4859243Sobrien#ifdef CLOSE_ON_EXEC
4959243Sobrien# ifndef SUNOS4
5059243Sobrien#  ifndef CLEX_DUPS
5159243Sobrien#   define CLEX_DUPS
5259243Sobrien#  endif /* CLEX_DUPS */
5359243Sobrien# endif /* !SUNOS4 */
5459243Sobrien#endif /* CLOSE_ON_EXEC */
5559243Sobrien
5659243Sobrien#if defined(__sparc__) || defined(sparc)
5759243Sobrien# if !defined(MACH) && SYSVREL == 0 && !defined(Lynx) && !defined(BSD4_4) && !defined(linux)
5859243Sobrien#  include <vfork.h>
5959243Sobrien# endif /* !MACH && SYSVREL == 0 && !Lynx && !BSD4_4 && !linux */
6059243Sobrien#endif /* __sparc__ || sparc */
6159243Sobrien
6259243Sobrien#ifdef VFORK
6359243Sobrienstatic	sigret_t	vffree	__P((int));
6459243Sobrien#endif
6559243Sobrienstatic	Char		*splicepipe	__P((struct command *, Char *));
6659243Sobrienstatic	void		 doio		__P((struct command *, int *, int *));
6759243Sobrienstatic	void		 chkclob	__P((char *));
6859243Sobrien
6959243Sobrien/*
7059243Sobrien * C shell
7159243Sobrien */
7259243Sobrien
7359243Sobrien/*
7459243Sobrien * For SVR4, there are problems with pipelines having the first process as
7559243Sobrien * the group leader.  The problem occurs when the first process exits before
7659243Sobrien * the others have a chance to setpgid().  This is because in SVR4 you can't
7759243Sobrien * have a zombie as a group leader.  The solution I have used is to reverse
7859243Sobrien * the order in which pipelines are started, making the last process the
7959243Sobrien * group leader.  (Note I am not using 'pipeline' in the generic sense -- I
8059243Sobrien * mean processes connected by '|'.)  I don't know yet if this causes other
8159243Sobrien * problems.
8259243Sobrien *
8359243Sobrien * All the changes for this are in execute(), and are enclosed in
8459243Sobrien * '#ifdef BACKPIPE'
8559243Sobrien *
8659243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991
8759243Sobrien */
8859243Sobrien
8959243Sobrien/*VARARGS 1*/
9059243Sobrienvoid
9159243Sobrienexecute(t, wanttty, pipein, pipeout)
9259243Sobrien    register struct command *t;
9359243Sobrien    int     wanttty;
9459243Sobrien    int *pipein, *pipeout;
9559243Sobrien{
9659243Sobrien#ifdef VFORK
9759243Sobrien    extern bool use_fork;	/* use fork() instead of vfork()? */
9859243Sobrien#endif
9959243Sobrien
10059243Sobrien    bool    forked = 0;
10159243Sobrien    struct biltins *bifunc;
10259243Sobrien    int     pid = 0;
10359243Sobrien    int     pv[2];
10459243Sobrien#ifdef BSDSIGS
10559243Sobrien    static sigmask_t csigmask;
10659243Sobrien#endif /* BSDSIGS */
10759243Sobrien#ifdef VFORK
10859243Sobrien    static int onosigchld = 0;
10959243Sobrien#endif /* VFORK */
11059243Sobrien    static int nosigchld = 0;
11159243Sobrien
11259243Sobrien    (void) &wanttty;
11359243Sobrien    (void) &forked;
11459243Sobrien    (void) &bifunc;
11559243Sobrien
11659243Sobrien    if (t == 0)
11759243Sobrien	return;
11859243Sobrien
11969408Sache#ifdef WINNT_NATIVE
12059243Sobrien    {
12159243Sobrien        if ((varval(STRNTslowexec) == STRNULL) &&
12259243Sobrien            !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds &&
12359243Sobrien            (intty || intact) && (t->t_dtyp == NODE_COMMAND) &&
12459243Sobrien	    !isbfunc(t)) {
12559243Sobrien	    if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
12659243Sobrien		(void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
12759243Sobrien	    Dfix(t);
12859243Sobrien            if (nt_try_fast_exec(t) == 0)
12959243Sobrien                return;
13059243Sobrien        }
13159243Sobrien    }
13269408Sache#endif /* WINNT_NATIVE */
13359243Sobrien
13459243Sobrien    /*
13559243Sobrien     * Ed hutchins@sgi.com & Dominic dbg@sgi.com
13659243Sobrien     * Sat Feb 25 03:13:11 PST 1995
13759243Sobrien     * try implicit cd if we have a 1 word command
13859243Sobrien     */
13959243Sobrien    if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] &&
14059243Sobrien	 t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) {
14159243Sobrien	Char sCName[MAXPATHLEN];
14259243Sobrien	Char *pCN;
14359243Sobrien	struct stat stbuf;
14459243Sobrien	char *pathname;
14559243Sobrien
14659243Sobrien	dollar(sCName, t->t_dcom[0]);
14759243Sobrien	pCN = sCName;
14859243Sobrien	if (pCN[0] == '~') {
14959243Sobrien	    Char sCPath[MAXPATHLEN];
15059243Sobrien	    Char *pCP = sCPath;
15159243Sobrien
15259243Sobrien	    ++pCN;
15359243Sobrien	    while (*pCN && *pCN != '/')
15459243Sobrien		*pCP++ = *pCN++;
15559243Sobrien	    *pCP = 0;
15659243Sobrien	    if (sCPath[0])
15759243Sobrien		gethdir(sCPath);
15859243Sobrien	    else
15959243Sobrien		(void) Strcpy(sCPath, varval(STRhome));
16059243Sobrien	    catn(sCPath, pCN, MAXPATHLEN);
16159243Sobrien	    (void) Strcpy(sCName, sCPath);
16259243Sobrien	}
16359243Sobrien
16459243Sobrien	pathname = short2str(sCName);
16559243Sobrien	/* if this is a dir, tack a "cd" on as the first arg */
16659243Sobrien	if ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode))
16769408Sache#ifdef WINNT_NATIVE
16859243Sobrien	    || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0')
16969408Sache#endif /* WINNT_NATIVE */
17059243Sobrien	) {
17159243Sobrien	    Char *vCD[2];
17259243Sobrien	    Char **ot_dcom = t->t_dcom;
17359243Sobrien
17459243Sobrien	    vCD[0] = Strsave(STRcd);
17559243Sobrien	    vCD[1] = NULL;
17659243Sobrien	    t->t_dcom = blkspl(vCD, ot_dcom);
17759243Sobrien	    if (implicit_cd > 1) {
17859243Sobrien		blkpr(t->t_dcom);
17959243Sobrien		xputchar( '\n' );
18059243Sobrien	    }
18159243Sobrien	    xfree((ptr_t) ot_dcom);
18259243Sobrien	}
18359243Sobrien    }
18459243Sobrien
18559243Sobrien    /*
18659243Sobrien     * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
18759243Sobrien     * Don't check for wantty > 0...
18859243Sobrien     */
18959243Sobrien    if (t->t_dflg & F_AMPERSAND)
19059243Sobrien	wanttty = 0;
19159243Sobrien    switch (t->t_dtyp) {
19259243Sobrien
19359243Sobrien    case NODE_COMMAND:
19459243Sobrien	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
19559243Sobrien	    (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
19659243Sobrien	if ((t->t_dflg & F_REPEAT) == 0)
19759243Sobrien	    Dfix(t);		/* $ " ' \ */
19859243Sobrien	if (t->t_dcom[0] == 0) {
19959243Sobrien	    return;
20059243Sobrien	}
20159243Sobrien	/*FALLTHROUGH*/
20259243Sobrien
20359243Sobrien    case NODE_PAREN:
20459243Sobrien#ifdef BACKPIPE
20559243Sobrien	if (t->t_dflg & F_PIPEIN)
20659243Sobrien	    mypipe(pipein);
20759243Sobrien#else /* !BACKPIPE */
20859243Sobrien	if (t->t_dflg & F_PIPEOUT)
20959243Sobrien	    mypipe(pipeout);
21059243Sobrien#endif /* BACKPIPE */
21159243Sobrien	/*
21259243Sobrien	 * Must do << early so parent will know where input pointer should be.
21359243Sobrien	 * If noexec then this is all we do.
21459243Sobrien	 */
21559243Sobrien	if (t->t_dflg & F_READ) {
21659243Sobrien	    (void) close(0);
21759243Sobrien	    heredoc(t->t_dlef);
21859243Sobrien	    if (noexec)
21959243Sobrien		(void) close(0);
22059243Sobrien	}
22159243Sobrien
22259243Sobrien	set(STRstatus, Strsave(STR0), VAR_READWRITE);
22359243Sobrien
22459243Sobrien	/*
22559243Sobrien	 * This mess is the necessary kludge to handle the prefix builtins:
22659243Sobrien	 * nice, nohup, time.  These commands can also be used by themselves,
22759243Sobrien	 * and this is not handled here. This will also work when loops are
22859243Sobrien	 * parsed.
22959243Sobrien	 */
23059243Sobrien	while (t->t_dtyp == NODE_COMMAND)
23159243Sobrien	    if (eq(t->t_dcom[0], STRnice)) {
23259243Sobrien		if (t->t_dcom[1]) {
23359243Sobrien		    if (strchr("+-", t->t_dcom[1][0])) {
23459243Sobrien			if (t->t_dcom[2]) {
23559243Sobrien			    setname("nice");
23659243Sobrien			    t->t_nice =
23759243Sobrien				getn(t->t_dcom[1]);
23859243Sobrien			    lshift(t->t_dcom, 2);
23959243Sobrien			    t->t_dflg |= F_NICE;
24059243Sobrien			}
24159243Sobrien			else
24259243Sobrien			    break;
24359243Sobrien		    }
24459243Sobrien		    else {
24559243Sobrien			t->t_nice = 4;
24659243Sobrien			lshift(t->t_dcom, 1);
24759243Sobrien			t->t_dflg |= F_NICE;
24859243Sobrien		    }
24959243Sobrien		}
25059243Sobrien		else
25159243Sobrien		    break;
25259243Sobrien	    }
25359243Sobrien	    else if (eq(t->t_dcom[0], STRnohup)) {
25459243Sobrien		if (t->t_dcom[1]) {
25559243Sobrien		    t->t_dflg |= F_NOHUP;
25659243Sobrien		    lshift(t->t_dcom, 1);
25759243Sobrien		}
25859243Sobrien		else
25959243Sobrien		    break;
26059243Sobrien	    }
26159243Sobrien	    else if (eq(t->t_dcom[0], STRhup)) {
26259243Sobrien		if (t->t_dcom[1]) {
26359243Sobrien		    t->t_dflg |= F_HUP;
26459243Sobrien		    lshift(t->t_dcom, 1);
26559243Sobrien		}
26659243Sobrien		else
26759243Sobrien		    break;
26859243Sobrien	    }
26959243Sobrien	    else if (eq(t->t_dcom[0], STRtime)) {
27059243Sobrien		if (t->t_dcom[1]) {
27159243Sobrien		    t->t_dflg |= F_TIME;
27259243Sobrien		    lshift(t->t_dcom, 1);
27359243Sobrien		}
27459243Sobrien		else
27559243Sobrien		    break;
27659243Sobrien	    }
27759243Sobrien#ifdef F_VER
27859243Sobrien	    else if (eq(t->t_dcom[0], STRver))
27959243Sobrien		if (t->t_dcom[1] && t->t_dcom[2]) {
28059243Sobrien		    setname("ver");
28159243Sobrien		    t->t_systype = getv(t->t_dcom[1]);
28259243Sobrien		    lshift(t->t_dcom, 2);
28359243Sobrien		    t->t_dflg |= F_VER;
28459243Sobrien		}
28559243Sobrien		else
28659243Sobrien		    break;
28759243Sobrien#endif  /* F_VER */
28859243Sobrien	    else
28959243Sobrien		break;
29059243Sobrien
29159243Sobrien	/* is it a command */
29259243Sobrien	if (t->t_dtyp == NODE_COMMAND) {
29359243Sobrien	    /*
29459243Sobrien	     * Check if we have a builtin function and remember which one.
29559243Sobrien	     */
29659243Sobrien	    bifunc = isbfunc(t);
29759243Sobrien 	    if (noexec && bifunc) {
29859243Sobrien		/*
29959243Sobrien		 * Continue for builtins that are part of the scripting language
30059243Sobrien		 */
30159243Sobrien		if (bifunc->bfunct != (bfunc_t)dobreak	&&
30259243Sobrien		    bifunc->bfunct != (bfunc_t)docontin	&&
30359243Sobrien		    bifunc->bfunct != (bfunc_t)doelse	&&
30459243Sobrien		    bifunc->bfunct != (bfunc_t)doend	&&
30559243Sobrien		    bifunc->bfunct != (bfunc_t)doforeach&&
30659243Sobrien		    bifunc->bfunct != (bfunc_t)dogoto	&&
30759243Sobrien		    bifunc->bfunct != (bfunc_t)doif	&&
30859243Sobrien		    bifunc->bfunct != (bfunc_t)dorepeat	&&
30959243Sobrien		    bifunc->bfunct != (bfunc_t)doswbrk	&&
31059243Sobrien		    bifunc->bfunct != (bfunc_t)doswitch	&&
31159243Sobrien		    bifunc->bfunct != (bfunc_t)dowhile	&&
31259243Sobrien		    bifunc->bfunct != (bfunc_t)dozip)
31359243Sobrien		    break;
31459243Sobrien	    }
31559243Sobrien	}
31659243Sobrien	else {			/* not a command */
31759243Sobrien	    bifunc = NULL;
31859243Sobrien	    if (noexec)
31959243Sobrien		break;
32059243Sobrien	}
32159243Sobrien
32283098Smp	/*
32383098Smp	 * GrP Executing a command - run jobcmd hook
32483098Smp	 * Don't run for builtins
32583098Smp	 * Don't run if we're not in a tty
32683098Smp	 * Don't run if we're not really executing
32783098Smp	 */
32883098Smp	if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty) {
32983098Smp	    Char *cmd = unparse(t);
33083098Smp	    job_cmd(cmd);
33183098Smp	    xfree(cmd);
33283098Smp	}
33383098Smp
33459243Sobrien	/*
33559243Sobrien	 * We fork only if we are timed, or are not the end of a parenthesized
33659243Sobrien	 * list and not a simple builtin function. Simple meaning one that is
33759243Sobrien	 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
33859243Sobrien	 * fork in some of these cases.
33959243Sobrien	 */
34059243Sobrien	/*
34159243Sobrien	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
34259243Sobrien	 * shell not to change dir!
34359243Sobrien	 */
34459243Sobrien#ifdef BACKPIPE
34559243Sobrien	/*
34659243Sobrien	 * Can't have NOFORK for the tail of a pipe - because it is not the
34759243Sobrien	 * last command spawned (even if it is at the end of a parenthesised
34859243Sobrien	 * list).
34959243Sobrien	 */
35059243Sobrien	if (t->t_dflg & F_PIPEIN)
35159243Sobrien	    t->t_dflg &= ~(F_NOFORK);
35259243Sobrien#endif /* BACKPIPE */
35359243Sobrien	if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd ||
35459243Sobrien		       bifunc->bfunct == (bfunc_t)dopushd ||
35559243Sobrien		       bifunc->bfunct == (bfunc_t)dopopd))
35659243Sobrien	    t->t_dflg &= ~(F_NICE);
35759243Sobrien	if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
35859243Sobrien	     (!bifunc || t->t_dflg &
35959243Sobrien	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) ||
36059243Sobrien	/*
36159243Sobrien	 * We have to fork for eval too.
36259243Sobrien	 */
36359243Sobrien	    (bifunc && (t->t_dflg & F_PIPEIN) != 0 &&
36469408Sache	     bifunc->bfunct == (bfunc_t)doeval)) {
36559243Sobrien#ifdef VFORK
36659243Sobrien	    if (t->t_dtyp == NODE_PAREN ||
36759243Sobrien		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc)
36859243Sobrien#endif /* VFORK */
36959243Sobrien	    {
37059243Sobrien		forked++;
37159243Sobrien		/*
37259243Sobrien		 * We need to block SIGCHLD here, so that if the process does
37359243Sobrien		 * not die before we can set the process group
37459243Sobrien		 */
37559243Sobrien		if (wanttty >= 0 && !nosigchld) {
37659243Sobrien#ifdef BSDSIGS
37759243Sobrien		    csigmask = sigblock(sigmask(SIGCHLD));
37859243Sobrien#else /* !BSDSIGS */
37959243Sobrien		    (void) sighold(SIGCHLD);
38059243Sobrien#endif /* BSDSIGS */
38159243Sobrien
38259243Sobrien		    nosigchld = 1;
38359243Sobrien		}
38459243Sobrien
38559243Sobrien		pid = pfork(t, wanttty);
38659243Sobrien		if (pid == 0 && nosigchld) {
38759243Sobrien#ifdef BSDSIGS
38859243Sobrien		    (void) sigsetmask(csigmask);
38959243Sobrien#else /* !BSDSIGS */
39059243Sobrien		    (void) sigrelse(SIGCHLD);
39159243Sobrien#endif /* BSDSIGS */
39259243Sobrien		    nosigchld = 0;
39359243Sobrien		}
39459243Sobrien		else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
39559243Sobrien		    backpid = pid;
39659243Sobrien	    }
39759243Sobrien
39859243Sobrien#ifdef VFORK
39959243Sobrien	    else {
40059243Sobrien		int     ochild, osetintr, ohaderr, odidfds;
40159243Sobrien		int     oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
40259243Sobrien		int     oisoutatty, oisdiagatty;
40359243Sobrien
40459243Sobrien# ifndef CLOSE_ON_EXEC
40559243Sobrien		int     odidcch;
40659243Sobrien# endif  /* !CLOSE_ON_EXEC */
40759243Sobrien# ifdef BSDSIGS
40859243Sobrien		sigmask_t omask, ocsigmask;
40959243Sobrien# endif /* BSDSIGS */
41059243Sobrien
41159243Sobrien		/*
41259243Sobrien		 * Prepare for the vfork by saving everything that the child
41359243Sobrien		 * corrupts before it exec's. Note that in some signal
41459243Sobrien		 * implementations which keep the signal info in user space
41559243Sobrien		 * (e.g. Sun's) it will also be necessary to save and restore
41659243Sobrien		 * the current sigvec's for the signals the child touches
41759243Sobrien		 * before it exec's.
41859243Sobrien		 */
41959243Sobrien
42059243Sobrien		/*
42159243Sobrien		 * Sooooo true... If this is a Sun, save the sigvec's. (Skip
42259243Sobrien		 * Gilbrech - 11/22/87)
42359243Sobrien		 */
42459243Sobrien# ifdef SAVESIGVEC
42559243Sobrien		sigvec_t savesv[NSIGSAVED];
42659243Sobrien		sigmask_t savesm;
42759243Sobrien
42859243Sobrien# endif /* SAVESIGVEC */
42959243Sobrien		if (wanttty >= 0 && !nosigchld && !noexec) {
43059243Sobrien# ifdef BSDSIGS
43159243Sobrien		    csigmask = sigblock(sigmask(SIGCHLD));
43259243Sobrien# else /* !BSDSIGS */
43359243Sobrien		    (void) sighold(SIGCHLD);
43459243Sobrien# endif  /* BSDSIGS */
43559243Sobrien		    nosigchld = 1;
43659243Sobrien		}
43759243Sobrien# ifdef BSDSIGS
43859243Sobrien		omask = sigblock(sigmask(SIGCHLD)|sigmask(SIGINT));
43959243Sobrien# else /* !BSDSIGS */
44059243Sobrien		(void) sighold(SIGCHLD);
44159243Sobrien		(void) sighold(SIGINT);
44259243Sobrien# endif  /* BSDSIGS */
44359243Sobrien		ochild = child;
44459243Sobrien		osetintr = setintr;
44559243Sobrien		ohaderr = haderr;
44659243Sobrien		odidfds = didfds;
44759243Sobrien# ifndef CLOSE_ON_EXEC
44859243Sobrien		odidcch = didcch;
44959243Sobrien# endif /* !CLOSE_ON_EXEC */
45059243Sobrien		oSHIN = SHIN;
45159243Sobrien		oSHOUT = SHOUT;
45259243Sobrien		oSHDIAG = SHDIAG;
45359243Sobrien		oOLDSTD = OLDSTD;
45459243Sobrien		otpgrp = tpgrp;
45559243Sobrien		oisoutatty = isoutatty;
45659243Sobrien		oisdiagatty = isdiagatty;
45759243Sobrien# ifdef BSDSIGS
45859243Sobrien		ocsigmask = csigmask;
45959243Sobrien# endif /* BSDSIGS */
46059243Sobrien		onosigchld = nosigchld;
46159243Sobrien		Vsav = Vdp = 0;
46259243Sobrien		Vexpath = 0;
46359243Sobrien		Vt = 0;
46459243Sobrien# ifdef SAVESIGVEC
46559243Sobrien		savesm = savesigvec(savesv);
46659243Sobrien# endif /* SAVESIGVEC */
46759243Sobrien		if (use_fork)
46859243Sobrien		    pid = fork();
46959243Sobrien		else
47059243Sobrien		    pid = vfork();
47159243Sobrien
47259243Sobrien		if (pid < 0) {
47359243Sobrien# ifdef BSDSIGS
47459243Sobrien#  ifdef SAVESIGVEC
47559243Sobrien		    restoresigvec(savesv, savesm);
47659243Sobrien#  endif /* SAVESIGVEC */
47759243Sobrien		    (void) sigsetmask(omask);
47859243Sobrien# else /* !BSDSIGS */
47959243Sobrien		    (void) sigrelse(SIGCHLD);
48059243Sobrien		    (void) sigrelse(SIGINT);
48159243Sobrien# endif  /* BSDSIGS */
48259243Sobrien		    stderror(ERR_NOPROC);
48359243Sobrien		}
48459243Sobrien		forked++;
48559243Sobrien		if (pid) {	/* parent */
48659243Sobrien# ifdef SAVESIGVEC
48759243Sobrien		    restoresigvec(savesv, savesm);
48859243Sobrien# endif /* SAVESIGVEC */
48959243Sobrien		    child = ochild;
49059243Sobrien		    setintr = osetintr;
49159243Sobrien		    haderr = ohaderr;
49259243Sobrien		    didfds = odidfds;
49359243Sobrien		    SHIN = oSHIN;
49459243Sobrien# ifndef CLOSE_ON_EXEC
49559243Sobrien		    didcch = odidcch;
49659243Sobrien# endif /* !CLOSE_ON_EXEC */
49759243Sobrien		    SHOUT = oSHOUT;
49859243Sobrien		    SHDIAG = oSHDIAG;
49959243Sobrien		    OLDSTD = oOLDSTD;
50059243Sobrien		    tpgrp = otpgrp;
50159243Sobrien		    isoutatty = oisoutatty;
50259243Sobrien		    isdiagatty = oisdiagatty;
50359243Sobrien# ifdef BSDSIGS
50459243Sobrien		    csigmask = ocsigmask;
50559243Sobrien# endif /* BSDSIGS */
50659243Sobrien		    nosigchld = onosigchld;
50759243Sobrien
50859243Sobrien		    xfree((ptr_t) Vsav);
50959243Sobrien		    Vsav = 0;
51059243Sobrien		    xfree((ptr_t) Vdp);
51159243Sobrien		    Vdp = 0;
51259243Sobrien		    xfree((ptr_t) Vexpath);
51359243Sobrien		    Vexpath = 0;
51459243Sobrien		    blkfree((Char **) Vt);
51559243Sobrien		    Vt = 0;
51659243Sobrien		    /* this is from pfork() */
51759243Sobrien		    palloc(pid, t);
51859243Sobrien# ifdef BSDSIGS
51959243Sobrien		    (void) sigsetmask(omask);
52059243Sobrien# else /* !BSDSIGS */
52159243Sobrien		    (void) sigrelse(SIGCHLD);
52259243Sobrien		    (void) sigrelse(SIGINT);
52359243Sobrien# endif  /* BSDSIGS */
52459243Sobrien		}
52559243Sobrien		else {		/* child */
52659243Sobrien		    /* this is from pfork() */
52759243Sobrien		    int     pgrp;
52859243Sobrien		    bool    ignint = 0;
52959243Sobrien		    if (nosigchld) {
53059243Sobrien# ifdef BSDSIGS
53159243Sobrien			(void) sigsetmask(csigmask);
53259243Sobrien# else /* !BSDSIGS */
53359243Sobrien			(void) sigrelse(SIGCHLD);
53459243Sobrien# endif /* BSDSIGS */
53559243Sobrien			nosigchld = 0;
53659243Sobrien		    }
53759243Sobrien
53859243Sobrien		    if (setintr)
53959243Sobrien			ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
54059243Sobrien				|| (gointr && eq(gointr, STRminus));
54159243Sobrien		    pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
54259243Sobrien		    child++;
54359243Sobrien		    if (setintr) {
54459243Sobrien			setintr = 0;
54559243Sobrien/*
54659243Sobrien * casts made right for SunOS 4.0 by Douglas C. Schmidt
54759243Sobrien * <schmidt%sunshine.ics.uci.edu@ROME.ICS.UCI.EDU>
54859243Sobrien * (thanks! -- PWP)
54959243Sobrien *
55059243Sobrien * ignint ifs cleaned by Johan Widen <mcvax!osiris.sics.se!jw@uunet.UU.NET>
55159243Sobrien * (thanks again)
55259243Sobrien */
55359243Sobrien			if (ignint) {
55459243Sobrien			    (void) signal(SIGINT, SIG_IGN);
55559243Sobrien			    (void) signal(SIGQUIT, SIG_IGN);
55659243Sobrien			}
55759243Sobrien			else {
55859243Sobrien			    (void) signal(SIGINT,  vffree);
55959243Sobrien			    (void) signal(SIGQUIT, SIG_DFL);
56059243Sobrien			}
56159243Sobrien# ifdef BSDJOBS
56259243Sobrien			if (wanttty >= 0) {
56359243Sobrien			    (void) signal(SIGTSTP, SIG_DFL);
56459243Sobrien			    (void) signal(SIGTTIN, SIG_DFL);
56559243Sobrien			    (void) signal(SIGTTOU, SIG_DFL);
56659243Sobrien			}
56759243Sobrien# endif /* BSDJOBS */
56859243Sobrien
56959243Sobrien			(void) signal(SIGTERM, parterm);
57059243Sobrien		    }
57159243Sobrien		    else if (tpgrp == -1 &&
57259243Sobrien			     (t->t_dflg & F_NOINTERRUPT)) {
57359243Sobrien			(void) signal(SIGINT, SIG_IGN);
57459243Sobrien			(void) signal(SIGQUIT, SIG_IGN);
57559243Sobrien		    }
57659243Sobrien
57759243Sobrien		    pgetty(wanttty, pgrp);
57859243Sobrien
57959243Sobrien		    if (t->t_dflg & F_NOHUP)
58059243Sobrien			(void) signal(SIGHUP, SIG_IGN);
58159243Sobrien		    if (t->t_dflg & F_HUP)
58259243Sobrien			(void) signal(SIGHUP, SIG_DFL);
58359243Sobrien		    if (t->t_dflg & F_NICE) {
58459243Sobrien			int nval = SIGN_EXTEND_CHAR(t->t_nice);
58559243Sobrien# ifdef BSDNICE
58683098Smp			if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno)
58783098Smp				stderror(ERR_SYSTEM, "setpriority",
58883098Smp				    strerror(errno));
58959243Sobrien# else /* !BSDNICE */
59059243Sobrien			(void) nice(nval);
59159243Sobrien# endif /* BSDNICE */
59259243Sobrien		    }
59359243Sobrien# ifdef F_VER
59459243Sobrien		    if (t->t_dflg & F_VER) {
59559243Sobrien			tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53);
59659243Sobrien			dohash(NULL, NULL);
59759243Sobrien		    }
59859243Sobrien# endif /* F_VER */
59959243Sobrien		}
60059243Sobrien
60159243Sobrien	    }
60259243Sobrien#endif /* VFORK */
60369408Sache	}
60459243Sobrien	if (pid != 0) {
60559243Sobrien	    /*
60659243Sobrien	     * It would be better if we could wait for the whole job when we
60759243Sobrien	     * knew the last process had been started.  Pwait, in fact, does
60859243Sobrien	     * wait for the whole job anyway, but this test doesn't really
60959243Sobrien	     * express our intentions.
61059243Sobrien	     */
61159243Sobrien#ifdef BACKPIPE
61259243Sobrien	    if (didfds == 0 && t->t_dflg & F_PIPEOUT) {
61359243Sobrien		(void) close(pipeout[0]);
61459243Sobrien		(void) close(pipeout[1]);
61559243Sobrien	    }
61659243Sobrien	    if ((t->t_dflg & F_PIPEIN) != 0)
61759243Sobrien		break;
61859243Sobrien#else /* !BACKPIPE */
61959243Sobrien	    if (didfds == 0 && t->t_dflg & F_PIPEIN) {
62059243Sobrien		(void) close(pipein[0]);
62159243Sobrien		(void) close(pipein[1]);
62259243Sobrien	    }
62359243Sobrien	    if ((t->t_dflg & F_PIPEOUT) != 0)
62459243Sobrien		break;
62559243Sobrien#endif /* BACKPIPE */
62659243Sobrien
62759243Sobrien	    if (nosigchld) {
62859243Sobrien#ifdef BSDSIGS
62959243Sobrien		(void) sigsetmask(csigmask);
63059243Sobrien#else /* !BSDSIGS */
63159243Sobrien		(void) sigrelse(SIGCHLD);
63259243Sobrien#endif /* BSDSIGS */
63359243Sobrien		nosigchld = 0;
63459243Sobrien	    }
63559243Sobrien	    if ((t->t_dflg & F_AMPERSAND) == 0)
63659243Sobrien		pwait();
63759243Sobrien	    break;
63859243Sobrien	}
63959243Sobrien
64059243Sobrien	doio(t, pipein, pipeout);
64159243Sobrien#ifdef BACKPIPE
64259243Sobrien	if (t->t_dflg & F_PIPEIN) {
64359243Sobrien	    (void) close(pipein[0]);
64459243Sobrien	    (void) close(pipein[1]);
64559243Sobrien	}
64659243Sobrien#else /* !BACKPIPE */
64759243Sobrien	if (t->t_dflg & F_PIPEOUT) {
64859243Sobrien	    (void) close(pipeout[0]);
64959243Sobrien	    (void) close(pipeout[1]);
65059243Sobrien	}
65159243Sobrien#endif /* BACKPIPE */
65259243Sobrien	/*
65359243Sobrien	 * Perform a builtin function. If we are not forked, arrange for
65459243Sobrien	 * possible stopping
65559243Sobrien	 */
65659243Sobrien	if (bifunc) {
65759243Sobrien	    func(t, bifunc);
65859243Sobrien	    if (forked)
65959243Sobrien		exitstat();
66059243Sobrien	    break;
66159243Sobrien	}
66259243Sobrien	if (t->t_dtyp != NODE_PAREN) {
66359243Sobrien	    doexec(t);
66459243Sobrien	    /* NOTREACHED */
66559243Sobrien	}
66659243Sobrien	/*
66759243Sobrien	 * For () commands must put new 0,1,2 in FSH* and recurse
66859243Sobrien	 */
66959243Sobrien	OLDSTD = dcopy(0, FOLDSTD);
67059243Sobrien	SHOUT = dcopy(1, FSHOUT);
67159243Sobrien	isoutatty = isatty(SHOUT);
67259243Sobrien	SHDIAG = dcopy(2, FSHDIAG);
67359243Sobrien	isdiagatty = isatty(SHDIAG);
67459243Sobrien	(void) close(SHIN);
67559243Sobrien	SHIN = -1;
67659243Sobrien#ifndef CLOSE_ON_EXEC
67759243Sobrien	didcch = 0;
67859243Sobrien#endif /* !CLOSE_ON_EXEC */
67959243Sobrien	didfds = 0;
68059243Sobrien	wanttty = -1;
68159243Sobrien	t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
68259243Sobrien	execute(t->t_dspr, wanttty, NULL, NULL);
68359243Sobrien	exitstat();
68459243Sobrien
68559243Sobrien    case NODE_PIPE:
68659243Sobrien#ifdef BACKPIPE
68759243Sobrien	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
68859243Sobrien			(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
68959243Sobrien	execute(t->t_dcdr, wanttty, pv, pipeout);
69059243Sobrien	t->t_dcar->t_dflg |= F_PIPEOUT |
69159243Sobrien	    (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
69259243Sobrien	execute(t->t_dcar, wanttty, pipein, pv);
69359243Sobrien#else /* !BACKPIPE */
69459243Sobrien	t->t_dcar->t_dflg |= F_PIPEOUT |
69559243Sobrien	    (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
69659243Sobrien	execute(t->t_dcar, wanttty, pipein, pv);
69759243Sobrien	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
69859243Sobrien			(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
69959243Sobrien	execute(t->t_dcdr, wanttty, pv, pipeout);
70059243Sobrien#endif /* BACKPIPE */
70159243Sobrien	break;
70259243Sobrien
70359243Sobrien    case NODE_LIST:
70459243Sobrien	if (t->t_dcar) {
70559243Sobrien	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
70659243Sobrien	    execute(t->t_dcar, wanttty, NULL, NULL);
70759243Sobrien	    /*
70859243Sobrien	     * In strange case of A&B make a new job after A
70959243Sobrien	     */
71059243Sobrien	    if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
71159243Sobrien		(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
71259243Sobrien		pendjob();
71359243Sobrien	}
71459243Sobrien	if (t->t_dcdr) {
71559243Sobrien	    t->t_dcdr->t_dflg |= t->t_dflg &
71659243Sobrien		(F_NOFORK | F_NOINTERRUPT);
71759243Sobrien	    execute(t->t_dcdr, wanttty, NULL, NULL);
71859243Sobrien	}
71959243Sobrien	break;
72059243Sobrien
72159243Sobrien    case NODE_OR:
72259243Sobrien    case NODE_AND:
72359243Sobrien	if (t->t_dcar) {
72459243Sobrien	    t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
72559243Sobrien	    execute(t->t_dcar, wanttty, NULL, NULL);
72659243Sobrien	    if ((getn(varval(STRstatus)) == 0) !=
72759243Sobrien		(t->t_dtyp == NODE_AND)) {
72859243Sobrien		return;
72959243Sobrien	    }
73059243Sobrien	}
73159243Sobrien	if (t->t_dcdr) {
73259243Sobrien	    t->t_dcdr->t_dflg |= t->t_dflg &
73359243Sobrien		(F_NOFORK | F_NOINTERRUPT);
73459243Sobrien	    execute(t->t_dcdr, wanttty, NULL, NULL);
73559243Sobrien	}
73659243Sobrien	break;
73759243Sobrien
73859243Sobrien    default:
73959243Sobrien	break;
74059243Sobrien    }
74159243Sobrien    /*
74259243Sobrien     * Fall through for all breaks from switch
74359243Sobrien     *
74459243Sobrien     * If there will be no more executions of this command, flush all file
74559243Sobrien     * descriptors. Places that turn on the F_REPEAT bit are responsible for
74659243Sobrien     * doing donefds after the last re-execution
74759243Sobrien     */
74859243Sobrien    if (didfds && !(t->t_dflg & F_REPEAT))
74959243Sobrien	donefds();
75059243Sobrien}
75159243Sobrien
75259243Sobrien#ifdef VFORK
75359243Sobrienstatic sigret_t
75459243Sobrien/*ARGSUSED*/
75559243Sobrienvffree(snum)
75659243Sobrienint snum;
75759243Sobrien{
75859243Sobrien    register Char **v;
75959243Sobrien
76059243Sobrien    USE(snum);
76159243Sobrien    if ((v = gargv) != 0) {
76259243Sobrien	gargv = 0;
76359243Sobrien	xfree((ptr_t) v);
76459243Sobrien    }
76559243Sobrien
76659243Sobrien    if ((v = pargv) != 0) {
76759243Sobrien	pargv = 0;
76859243Sobrien	xfree((ptr_t) v);
76959243Sobrien    }
77059243Sobrien
77159243Sobrien    _exit(1);
77259243Sobrien#ifndef SIGVOID
77359243Sobrien    /*NOTREACHED*/
77459243Sobrien    return(0);
77559243Sobrien#endif /* SIGVOID */
77659243Sobrien}
77759243Sobrien#endif /* VFORK */
77859243Sobrien
77959243Sobrien/*
78059243Sobrien * Expand and glob the words after an i/o redirection.
78159243Sobrien * If more than one word is generated, then update the command vector.
78259243Sobrien *
78359243Sobrien * This is done differently in all the shells:
78459243Sobrien * 1. in the bourne shell and ksh globbing is not performed
78559243Sobrien * 2. Bash/csh say ambiguous
78659243Sobrien * 3. zsh does i/o to/from all the files
78759243Sobrien * 4. itcsh concatenates the words.
78859243Sobrien *
78959243Sobrien * I don't know what is best to do. I think that Ambiguous is better
79059243Sobrien * than restructuring the command vector, because the user can get
79159243Sobrien * unexpected results. In any case, the command vector restructuring
79259243Sobrien * code is present and the user can choose it by setting noambiguous
79359243Sobrien */
79459243Sobrienstatic Char *
79559243Sobriensplicepipe(t, cp)
79659243Sobrien    register struct command *t;
79759243Sobrien    Char *cp;	/* word after < or > */
79859243Sobrien{
79959243Sobrien    Char *blk[2];
80059243Sobrien
80159243Sobrien    if (adrof(STRnoambiguous)) {
80259243Sobrien	Char **pv;
80359243Sobrien
80459243Sobrien	blk[0] = Dfix1(cp); /* expand $ */
80559243Sobrien	blk[1] = NULL;
80659243Sobrien
80759243Sobrien	gflag = 0, tglob(blk);
80859243Sobrien	if (gflag) {
80959243Sobrien	    pv = globall(blk);
81059243Sobrien	    if (pv == NULL) {
81159243Sobrien		setname(short2str(blk[0]));
81259243Sobrien		xfree((ptr_t) blk[0]);
81359243Sobrien		stderror(ERR_NAME | ERR_NOMATCH);
81459243Sobrien	    }
81559243Sobrien	    gargv = NULL;
81659243Sobrien	    if (pv[1] != NULL) { /* we need to fix the command vector */
81759243Sobrien		Char **av = blkspl(t->t_dcom, &pv[1]);
81859243Sobrien		xfree((ptr_t) t->t_dcom);
81959243Sobrien		t->t_dcom = av;
82059243Sobrien	    }
82159243Sobrien	    xfree((ptr_t) blk[0]);
82259243Sobrien	    blk[0] = pv[0];
82359243Sobrien	    xfree((ptr_t) pv);
82459243Sobrien	}
82559243Sobrien    }
82659243Sobrien    else {
82759243Sobrien	Char buf[BUFSIZE];
82859243Sobrien
82959243Sobrien	(void) Strcpy(buf, blk[1] = Dfix1(cp));
83059243Sobrien	xfree((ptr_t) blk[1]);
83159243Sobrien	blk[0] = globone(buf, G_ERROR);
83259243Sobrien    }
83359243Sobrien    return(blk[0]);
83459243Sobrien}
83559243Sobrien
83659243Sobrien/*
83759243Sobrien * Perform io redirection.
83859243Sobrien * We may or maynot be forked here.
83959243Sobrien */
84059243Sobrienstatic void
84159243Sobriendoio(t, pipein, pipeout)
84259243Sobrien    register struct command *t;
84359243Sobrien    int    *pipein, *pipeout;
84459243Sobrien{
84559243Sobrien    register int fd;
84659243Sobrien    register Char *cp;
84759243Sobrien    register unsigned long flags = t->t_dflg;
84859243Sobrien
84959243Sobrien    if (didfds || (flags & F_REPEAT))
85059243Sobrien	return;
85159243Sobrien    if ((flags & F_READ) == 0) {/* F_READ already done */
85259243Sobrien	if (t->t_dlef) {
85359243Sobrien	    char    tmp[MAXPATHLEN+1];
85459243Sobrien
85559243Sobrien	    /*
85659243Sobrien	     * so < /dev/std{in,out,err} work
85759243Sobrien	     */
85859243Sobrien	    (void) dcopy(SHIN, 0);
85959243Sobrien	    (void) dcopy(SHOUT, 1);
86059243Sobrien	    (void) dcopy(SHDIAG, 2);
86159243Sobrien	    cp = splicepipe(t, t->t_dlef);
86259243Sobrien	    (void) strncpy(tmp, short2str(cp), MAXPATHLEN);
86359243Sobrien	    tmp[MAXPATHLEN] = '\0';
86459243Sobrien	    xfree((ptr_t) cp);
86559243Sobrien	    if ((fd = open(tmp, O_RDONLY)) < 0)
86659243Sobrien		stderror(ERR_SYSTEM, tmp, strerror(errno));
86759243Sobrien#ifdef O_LARGEFILE
86859243Sobrien	    /* allow input files larger than 2Gb  */
86959243Sobrien	    (void) fcntl(fd, O_LARGEFILE, 0);
87059243Sobrien#endif /* O_LARGEFILE */
87159243Sobrien	    (void) dmove(fd, 0);
87259243Sobrien	}
87359243Sobrien	else if (flags & F_PIPEIN) {
87459243Sobrien	    (void) close(0);
87559243Sobrien	    (void) dup(pipein[0]);
87659243Sobrien	    (void) close(pipein[0]);
87759243Sobrien	    (void) close(pipein[1]);
87859243Sobrien	}
87959243Sobrien	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
88059243Sobrien	    (void) close(0);
88159243Sobrien	    (void) open(_PATH_DEVNULL, O_RDONLY);
88259243Sobrien	}
88359243Sobrien	else {
88459243Sobrien	    (void) close(0);
88559243Sobrien	    (void) dup(OLDSTD);
88659243Sobrien#if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
88759243Sobrien	    /*
88859243Sobrien	     * PWP: Unlike Bezerkeley 4.3, FIONCLEX for Pyramid is preserved
88959243Sobrien	     * across dup()s, so we have to UNSET it here or else we get a
89059243Sobrien	     * command with NO stdin, stdout, or stderr at all (a bad thing
89159243Sobrien	     * indeed)
89259243Sobrien	     */
89359243Sobrien	    (void) close_on_exec(0, 0);
89459243Sobrien#endif /* CLOSE_ON_EXEC && CLEX_DUPS */
89559243Sobrien	}
89659243Sobrien    }
89759243Sobrien    if (t->t_drit) {
89859243Sobrien	char    tmp[MAXPATHLEN+1];
89959243Sobrien
90059243Sobrien	cp = splicepipe(t, t->t_drit);
90159243Sobrien	(void) strncpy(tmp, short2str(cp), MAXPATHLEN);
90259243Sobrien	tmp[MAXPATHLEN] = '\0';
90359243Sobrien	xfree((ptr_t) cp);
90459243Sobrien	/*
90559243Sobrien	 * so > /dev/std{out,err} work
90659243Sobrien	 */
90759243Sobrien	(void) dcopy(SHOUT, 1);
90859243Sobrien	(void) dcopy(SHDIAG, 2);
90959243Sobrien	if ((flags & F_APPEND) != 0) {
91059243Sobrien#ifdef O_APPEND
91159243Sobrien	    fd = open(tmp, O_WRONLY | O_APPEND);
91259243Sobrien#else /* !O_APPEND */
91359243Sobrien	    fd = open(tmp, O_WRONLY);
91459243Sobrien	    (void) lseek(fd, (off_t) 0, L_XTND);
91559243Sobrien#endif /* O_APPEND */
91659243Sobrien	}
91759243Sobrien	else
91859243Sobrien	    fd = 0;
91959243Sobrien	if ((flags & F_APPEND) == 0 || fd == -1) {
92059243Sobrien	    if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
92159243Sobrien		if (flags & F_APPEND)
92259243Sobrien		    stderror(ERR_SYSTEM, tmp, strerror(errno));
92359243Sobrien		chkclob(tmp);
92459243Sobrien	    }
92559243Sobrien	    if ((fd = creat(tmp, 0666)) < 0)
92659243Sobrien		stderror(ERR_SYSTEM, tmp, strerror(errno));
92759243Sobrien#ifdef O_LARGEFILE
92859243Sobrien	    /* allow input files larger than 2Gb  */
92959243Sobrien	    (void) fcntl(fd, O_LARGEFILE, 0);
93059243Sobrien#endif /* O_LARGEFILE */
93159243Sobrien	}
93259243Sobrien	(void) dmove(fd, 1);
93359243Sobrien	is1atty = isatty(1);
93459243Sobrien    }
93559243Sobrien    else if (flags & F_PIPEOUT) {
93659243Sobrien	(void) close(1);
93759243Sobrien	(void) dup(pipeout[1]);
93859243Sobrien	is1atty = 0;
93959243Sobrien    }
94059243Sobrien    else {
94159243Sobrien	(void) close(1);
94259243Sobrien	(void) dup(SHOUT);
94359243Sobrien	is1atty = isoutatty;
94459243Sobrien# if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
94559243Sobrien	(void) close_on_exec(1, 0);
94659243Sobrien# endif /* CLOSE_ON_EXEC && CLEX_DUPS */
94759243Sobrien    }
94859243Sobrien
94959243Sobrien    (void) close(2);
95059243Sobrien    if (flags & F_STDERR) {
95159243Sobrien	(void) dup(1);
95259243Sobrien	is2atty = is1atty;
95359243Sobrien    }
95459243Sobrien    else {
95559243Sobrien	(void) dup(SHDIAG);
95659243Sobrien	is2atty = isdiagatty;
95759243Sobrien# if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
95859243Sobrien	(void) close_on_exec(2, 0);
95959243Sobrien# endif /* CLOSE_ON_EXEC && CLEX_DUPS */
96059243Sobrien    }
96159243Sobrien    didfds = 1;
96259243Sobrien}
96359243Sobrien
96459243Sobrienvoid
96559243Sobrienmypipe(pv)
96659243Sobrien    register int *pv;
96759243Sobrien{
96859243Sobrien
96959243Sobrien    if (pipe(pv) < 0)
97059243Sobrien	goto oops;
97159243Sobrien    pv[0] = dmove(pv[0], -1);
97259243Sobrien    pv[1] = dmove(pv[1], -1);
97359243Sobrien    if (pv[0] >= 0 && pv[1] >= 0)
97459243Sobrien	return;
97559243Sobrienoops:
97659243Sobrien    stderror(ERR_PIPE);
97759243Sobrien}
97859243Sobrien
97959243Sobrienstatic void
98059243Sobrienchkclob(cp)
98159243Sobrien    register char *cp;
98259243Sobrien{
98359243Sobrien    struct stat stb;
98459243Sobrien
98559243Sobrien    if (stat(cp, &stb) < 0)
98659243Sobrien	return;
98759243Sobrien    if (S_ISCHR(stb.st_mode))
98859243Sobrien	return;
98959243Sobrien    stderror(ERR_EXISTS, cp);
99059243Sobrien}
991