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