159243Sobrien/*
259243Sobrien * sh.sem.c: I/O redirections and job forking. A touchy issue!
359243Sobrien *	     Most stuff with builtins is incorrect
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien#include "tc.h"
3559243Sobrien#include "tw.h"
3669408Sache#ifdef WINNT_NATIVE
3759243Sobrien#include "nt.const.h"
3869408Sache#endif /*WINNT_NATIVE*/
3959243Sobrien
4059243Sobrien#ifdef CLOSE_ON_EXEC
4159243Sobrien# ifndef SUNOS4
4259243Sobrien#  ifndef CLEX_DUPS
4359243Sobrien#   define CLEX_DUPS
4459243Sobrien#  endif /* CLEX_DUPS */
4559243Sobrien# endif /* !SUNOS4 */
4659243Sobrien#endif /* CLOSE_ON_EXEC */
4759243Sobrien
4859243Sobrien#if defined(__sparc__) || defined(sparc)
49231990Smp# if !defined(MACH) && SYSVREL == 0 && !defined(Lynx) && !defined(BSD4_4) && !defined(__linux__) && !defined(__GNU__) && !defined(__GLIBC__)
5059243Sobrien#  include <vfork.h>
51145479Smp# endif /* !MACH && SYSVREL == 0 && !Lynx && !BSD4_4 && !glibc */
5259243Sobrien#endif /* __sparc__ || sparc */
5359243Sobrien
5459243Sobrien#ifdef VFORK
55167465Smpstatic	void		vffree		(int);
5659243Sobrien#endif
57167465Smpstatic	Char		*splicepipe	(struct command *, Char *);
58167465Smpstatic	void		 doio		(struct command *, int *, int *);
59167465Smpstatic	void		 chkclob	(const char *);
6059243Sobrien
6159243Sobrien/*
6259243Sobrien * C shell
6359243Sobrien */
6459243Sobrien
6559243Sobrien/*
6659243Sobrien * For SVR4, there are problems with pipelines having the first process as
6759243Sobrien * the group leader.  The problem occurs when the first process exits before
6859243Sobrien * the others have a chance to setpgid().  This is because in SVR4 you can't
6959243Sobrien * have a zombie as a group leader.  The solution I have used is to reverse
7059243Sobrien * the order in which pipelines are started, making the last process the
7159243Sobrien * group leader.  (Note I am not using 'pipeline' in the generic sense -- I
7259243Sobrien * mean processes connected by '|'.)  I don't know yet if this causes other
7359243Sobrien * problems.
7459243Sobrien *
7559243Sobrien * All the changes for this are in execute(), and are enclosed in
7659243Sobrien * '#ifdef BACKPIPE'
7759243Sobrien *
7859243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991
7959243Sobrien */
8059243Sobrien
8159243Sobrien/*VARARGS 1*/
8259243Sobrienvoid
83167465Smpexecute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
84167465Smp    int do_glob)
8559243Sobrien{
86145479Smp    int    forked = 0;
87167465Smp    const struct biltins * volatile bifunc;
88167465Smp    pid_t pid = 0;
8959243Sobrien    int     pv[2];
90167465Smp    sigset_t set;
91167465Smp    static sigset_t csigset;
9259243Sobrien#ifdef VFORK
9359243Sobrien    static int onosigchld = 0;
9459243Sobrien#endif /* VFORK */
9559243Sobrien    static int nosigchld = 0;
9659243Sobrien
9759243Sobrien    (void) &wanttty;
9859243Sobrien    (void) &forked;
9959243Sobrien    (void) &bifunc;
10059243Sobrien
10159243Sobrien    if (t == 0)
10259243Sobrien	return;
10359243Sobrien
10469408Sache#ifdef WINNT_NATIVE
10559243Sobrien    {
10659243Sobrien        if ((varval(STRNTslowexec) == STRNULL) &&
10759243Sobrien            !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds &&
10859243Sobrien            (intty || intact) && (t->t_dtyp == NODE_COMMAND) &&
10959243Sobrien	    !isbfunc(t)) {
11059243Sobrien	    if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
11159243Sobrien		(void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
11259243Sobrien	    Dfix(t);
11359243Sobrien            if (nt_try_fast_exec(t) == 0)
11459243Sobrien                return;
11559243Sobrien        }
11659243Sobrien    }
11769408Sache#endif /* WINNT_NATIVE */
11859243Sobrien
11959243Sobrien    /*
12059243Sobrien     * Ed hutchins@sgi.com & Dominic dbg@sgi.com
12159243Sobrien     * Sat Feb 25 03:13:11 PST 1995
12259243Sobrien     * try implicit cd if we have a 1 word command
12359243Sobrien     */
12459243Sobrien    if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] &&
12559243Sobrien	 t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) {
126167465Smp	Char *sCName;
12759243Sobrien	struct stat stbuf;
12859243Sobrien	char *pathname;
12959243Sobrien
130167465Smp	sCName = dollar(t->t_dcom[0]);
131167465Smp	if (sCName != NULL && sCName[0] == '~') {
132167465Smp	    struct Strbuf buf = Strbuf_INIT;
133167465Smp	    const Char *name_end;
13459243Sobrien
135167465Smp	    for (name_end = sCName + 1; *name_end != '\0' && *name_end != '/';
136167465Smp		 name_end++)
137167465Smp		continue;
138167465Smp	    if (name_end != sCName + 1) {
139167465Smp		Char *name, *home;
140167465Smp
141167465Smp		name = Strnsave(sCName + 1, name_end - (sCName + 1));
142167465Smp		home = gethdir(name);
143167465Smp		if (home != NULL) {
144167465Smp		    Strbuf_append(&buf, home);
145167465Smp		    xfree(home);
146167465Smp		} else
147167465Smp		    Strbuf_append(&buf, name);
148167465Smp		xfree(name);
149167465Smp	    } else
150167465Smp		Strbuf_append(&buf, varval(STRhome));
151167465Smp	    Strbuf_append(&buf, name_end);
152167465Smp	    xfree(sCName);
153167465Smp	    sCName = Strbuf_finish(&buf);
15459243Sobrien	}
155167465Smp
15659243Sobrien	pathname = short2str(sCName);
157167465Smp	xfree(sCName);
15859243Sobrien	/* if this is a dir, tack a "cd" on as the first arg */
159167465Smp	if (pathname != NULL &&
160167465Smp	    ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode))
16169408Sache#ifdef WINNT_NATIVE
162167465Smp	     || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0')
16369408Sache#endif /* WINNT_NATIVE */
164167465Smp	     )) {
16559243Sobrien	    Char *vCD[2];
16659243Sobrien	    Char **ot_dcom = t->t_dcom;
16759243Sobrien
16859243Sobrien	    vCD[0] = Strsave(STRcd);
16959243Sobrien	    vCD[1] = NULL;
17059243Sobrien	    t->t_dcom = blkspl(vCD, ot_dcom);
171167465Smp	    xfree(ot_dcom);
17259243Sobrien	    if (implicit_cd > 1) {
17359243Sobrien		blkpr(t->t_dcom);
17459243Sobrien		xputchar( '\n' );
17559243Sobrien	    }
17659243Sobrien	}
17759243Sobrien    }
17859243Sobrien
17959243Sobrien    /*
18059243Sobrien     * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
18159243Sobrien     * Don't check for wantty > 0...
18259243Sobrien     */
18359243Sobrien    if (t->t_dflg & F_AMPERSAND)
18459243Sobrien	wanttty = 0;
18559243Sobrien    switch (t->t_dtyp) {
18659243Sobrien
18759243Sobrien    case NODE_COMMAND:
18859243Sobrien	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
189167465Smp	    memmove(t->t_dcom[0], t->t_dcom[0] + 1,
190167465Smp		    (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0]));
19159243Sobrien	if ((t->t_dflg & F_REPEAT) == 0)
19259243Sobrien	    Dfix(t);		/* $ " ' \ */
19359243Sobrien	if (t->t_dcom[0] == 0) {
19459243Sobrien	    return;
19559243Sobrien	}
19659243Sobrien	/*FALLTHROUGH*/
19759243Sobrien
19859243Sobrien    case NODE_PAREN:
19959243Sobrien#ifdef BACKPIPE
20059243Sobrien	if (t->t_dflg & F_PIPEIN)
20159243Sobrien	    mypipe(pipein);
20259243Sobrien#else /* !BACKPIPE */
20359243Sobrien	if (t->t_dflg & F_PIPEOUT)
20459243Sobrien	    mypipe(pipeout);
20559243Sobrien#endif /* BACKPIPE */
20659243Sobrien	/*
20759243Sobrien	 * Must do << early so parent will know where input pointer should be.
20859243Sobrien	 * If noexec then this is all we do.
20959243Sobrien	 */
21059243Sobrien	if (t->t_dflg & F_READ) {
211316957Sdchagin	    int old_pintr_disabled;
212316957Sdchagin
213167465Smp	    xclose(0);
214316957Sdchagin	    if (setintr)
215316957Sdchagin		pintr_push_enable(&old_pintr_disabled);
21659243Sobrien	    heredoc(t->t_dlef);
217316957Sdchagin	    if (setintr)
218316957Sdchagin		cleanup_until(&old_pintr_disabled);
21959243Sobrien	    if (noexec)
220167465Smp		xclose(0);
22159243Sobrien	}
22259243Sobrien
223167465Smp	setcopy(STRstatus, STR0, VAR_READWRITE);
22459243Sobrien
22559243Sobrien	/*
22659243Sobrien	 * This mess is the necessary kludge to handle the prefix builtins:
22759243Sobrien	 * nice, nohup, time.  These commands can also be used by themselves,
22859243Sobrien	 * and this is not handled here. This will also work when loops are
22959243Sobrien	 * parsed.
23059243Sobrien	 */
23159243Sobrien	while (t->t_dtyp == NODE_COMMAND)
23259243Sobrien	    if (eq(t->t_dcom[0], STRnice)) {
23359243Sobrien		if (t->t_dcom[1]) {
23459243Sobrien		    if (strchr("+-", t->t_dcom[1][0])) {
23559243Sobrien			if (t->t_dcom[2]) {
23659243Sobrien			    setname("nice");
237231990Smp			    t->t_nice = (unsigned char)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);
297167465Smp 	    if (noexec) {
29859243Sobrien		/*
29959243Sobrien		 * Continue for builtins that are part of the scripting language
30059243Sobrien		 */
301167465Smp		if (bifunc == NULL)
302167465Smp		    break;
30359243Sobrien		if (bifunc->bfunct != (bfunc_t)dobreak	&&
30459243Sobrien		    bifunc->bfunct != (bfunc_t)docontin	&&
30559243Sobrien		    bifunc->bfunct != (bfunc_t)doelse	&&
30659243Sobrien		    bifunc->bfunct != (bfunc_t)doend	&&
30759243Sobrien		    bifunc->bfunct != (bfunc_t)doforeach&&
30859243Sobrien		    bifunc->bfunct != (bfunc_t)dogoto	&&
30959243Sobrien		    bifunc->bfunct != (bfunc_t)doif	&&
31059243Sobrien		    bifunc->bfunct != (bfunc_t)dorepeat	&&
31159243Sobrien		    bifunc->bfunct != (bfunc_t)doswbrk	&&
31259243Sobrien		    bifunc->bfunct != (bfunc_t)doswitch	&&
31359243Sobrien		    bifunc->bfunct != (bfunc_t)dowhile	&&
31459243Sobrien		    bifunc->bfunct != (bfunc_t)dozip)
31559243Sobrien		    break;
31659243Sobrien	    }
31759243Sobrien	}
31859243Sobrien	else {			/* not a command */
31959243Sobrien	    bifunc = NULL;
32059243Sobrien	    if (noexec)
32159243Sobrien		break;
32259243Sobrien	}
32359243Sobrien
32483098Smp	/*
32583098Smp	 * GrP Executing a command - run jobcmd hook
32683098Smp	 * Don't run for builtins
32783098Smp	 * Don't run if we're not in a tty
32883098Smp	 * Don't run if we're not really executing
32983098Smp	 */
330195609Smp	/*
331195609Smp	 * CR  -  Charles Ross Aug 2005
332195609Smp	 * added "isoutatty".
333195609Smp	 * The new behavior is that the jobcmd won't be executed
334195609Smp	 * if stdout (SHOUT) isnt attached to a tty.. IE when
335195609Smp	 * redirecting, or using backquotes etc..
336195609Smp	 */
337195609Smp	if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty && isoutatty) {
33883098Smp	    Char *cmd = unparse(t);
339167465Smp
340167465Smp	    cleanup_push(cmd, xfree);
34183098Smp	    job_cmd(cmd);
342167465Smp	    cleanup_until(cmd);
34383098Smp	}
34483098Smp
34559243Sobrien	/*
34659243Sobrien	 * We fork only if we are timed, or are not the end of a parenthesized
34759243Sobrien	 * list and not a simple builtin function. Simple meaning one that is
34859243Sobrien	 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
34959243Sobrien	 * fork in some of these cases.
35059243Sobrien	 */
35159243Sobrien#ifdef BACKPIPE
35259243Sobrien	/*
35359243Sobrien	 * Can't have NOFORK for the tail of a pipe - because it is not the
35459243Sobrien	 * last command spawned (even if it is at the end of a parenthesised
35559243Sobrien	 * list).
35659243Sobrien	 */
35759243Sobrien	if (t->t_dflg & F_PIPEIN)
35859243Sobrien	    t->t_dflg &= ~(F_NOFORK);
359316957Sdchagin#else
360316957Sdchagin	/*
361316957Sdchagin	 * "command | builtin" may cause major misbehaviour as noted in
362316957Sdchagin	 * in the BUGS file entry
363316957Sdchagin	 * Subject: Redirected input to built-in functions misbehaves badly
364316957Sdchagin	 * forking when the builtin is the end of the pipe corrects the
365316957Sdchagin	 * problem.
366316957Sdchagin	 */
367316957Sdchagin	if (bifunc && (t->t_dflg & F_PIPEIN))
368316957Sdchagin	    t->t_dflg &= ~(F_NOFORK);
36959243Sobrien#endif /* BACKPIPE */
370316957Sdchagin	/*
371316957Sdchagin	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
372316957Sdchagin	 * shell not to change dir! (XXX: but only for nice?)
373316957Sdchagin	 */
37459243Sobrien	if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd ||
37559243Sobrien		       bifunc->bfunct == (bfunc_t)dopushd ||
37659243Sobrien		       bifunc->bfunct == (bfunc_t)dopopd))
37759243Sobrien	    t->t_dflg &= ~(F_NICE);
378316957Sdchagin
37959243Sobrien	if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
38059243Sobrien	     (!bifunc || t->t_dflg &
38159243Sobrien	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) ||
38259243Sobrien	/*
38359243Sobrien	 * We have to fork for eval too.
38459243Sobrien	 */
38559243Sobrien	    (bifunc && (t->t_dflg & F_PIPEIN) != 0 &&
38669408Sache	     bifunc->bfunct == (bfunc_t)doeval)) {
38759243Sobrien#ifdef VFORK
38859243Sobrien	    if (t->t_dtyp == NODE_PAREN ||
38959243Sobrien		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc)
39059243Sobrien#endif /* VFORK */
39159243Sobrien	    {
39259243Sobrien		forked++;
39359243Sobrien		/*
39459243Sobrien		 * We need to block SIGCHLD here, so that if the process does
39559243Sobrien		 * not die before we can set the process group
39659243Sobrien		 */
39759243Sobrien		if (wanttty >= 0 && !nosigchld) {
398167465Smp		    sigemptyset(&set);
399167465Smp		    sigaddset(&set, SIGCHLD);
400167465Smp		    (void)sigprocmask(SIG_BLOCK, &set, &csigset);
40159243Sobrien
40259243Sobrien		    nosigchld = 1;
40359243Sobrien		}
40459243Sobrien
40559243Sobrien		pid = pfork(t, wanttty);
40659243Sobrien		if (pid == 0 && nosigchld) {
407167465Smp		    sigprocmask(SIG_SETMASK, &csigset, NULL);
40859243Sobrien		    nosigchld = 0;
40959243Sobrien		}
41059243Sobrien		else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
41159243Sobrien		    backpid = pid;
41259243Sobrien	    }
41359243Sobrien
41459243Sobrien#ifdef VFORK
41559243Sobrien	    else {
41659243Sobrien		int     ochild, osetintr, ohaderr, odidfds;
41759243Sobrien		int     oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
41859243Sobrien		int     oisoutatty, oisdiagatty;
419167465Smp		sigset_t oset, ocsigset;
42059243Sobrien# ifndef CLOSE_ON_EXEC
42159243Sobrien		int     odidcch;
42259243Sobrien# endif  /* !CLOSE_ON_EXEC */
42359243Sobrien
42459243Sobrien		/*
42559243Sobrien		 * Prepare for the vfork by saving everything that the child
42659243Sobrien		 * corrupts before it exec's. Note that in some signal
42759243Sobrien		 * implementations which keep the signal info in user space
42859243Sobrien		 * (e.g. Sun's) it will also be necessary to save and restore
42959243Sobrien		 * the current sigvec's for the signals the child touches
43059243Sobrien		 * before it exec's.
43159243Sobrien		 */
43259243Sobrien
43359243Sobrien		/*
43459243Sobrien		 * Sooooo true... If this is a Sun, save the sigvec's. (Skip
43559243Sobrien		 * Gilbrech - 11/22/87)
43659243Sobrien		 */
43759243Sobrien# ifdef SAVESIGVEC
438167465Smp		struct sigaction savesv[NSIGSAVED];
439167465Smp		sigset_t savesm;
44059243Sobrien
44159243Sobrien# endif /* SAVESIGVEC */
44259243Sobrien		if (wanttty >= 0 && !nosigchld && !noexec) {
443167465Smp		    sigemptyset(&set);
444167465Smp		    sigaddset(&set, SIGCHLD);
445167465Smp		    (void)sigprocmask(SIG_BLOCK, &set, &csigset);
44659243Sobrien		    nosigchld = 1;
44759243Sobrien		}
448167465Smp		sigemptyset(&set);
449167465Smp		sigaddset(&set, SIGCHLD);
450167465Smp		sigaddset(&set, SIGINT);
451167465Smp		(void)sigprocmask(SIG_BLOCK, &set, &oset);
45259243Sobrien		ochild = child;
45359243Sobrien		osetintr = setintr;
45459243Sobrien		ohaderr = haderr;
45559243Sobrien		odidfds = didfds;
45659243Sobrien# ifndef CLOSE_ON_EXEC
45759243Sobrien		odidcch = didcch;
45859243Sobrien# endif /* !CLOSE_ON_EXEC */
45959243Sobrien		oSHIN = SHIN;
46059243Sobrien		oSHOUT = SHOUT;
46159243Sobrien		oSHDIAG = SHDIAG;
46259243Sobrien		oOLDSTD = OLDSTD;
46359243Sobrien		otpgrp = tpgrp;
46459243Sobrien		oisoutatty = isoutatty;
46559243Sobrien		oisdiagatty = isdiagatty;
466167465Smp		ocsigset = csigset;
46759243Sobrien		onosigchld = nosigchld;
46859243Sobrien		Vsav = Vdp = 0;
46959243Sobrien		Vexpath = 0;
47059243Sobrien		Vt = 0;
47159243Sobrien# ifdef SAVESIGVEC
472167465Smp		savesigvec(savesv, savesm);
47359243Sobrien# endif /* SAVESIGVEC */
47459243Sobrien		if (use_fork)
47559243Sobrien		    pid = fork();
47659243Sobrien		else
47759243Sobrien		    pid = vfork();
47859243Sobrien
47959243Sobrien		if (pid < 0) {
480167465Smp# ifdef SAVESIGVEC
48159243Sobrien		    restoresigvec(savesv, savesm);
482167465Smp# endif /* SAVESIGVEC */
483167465Smp		    sigprocmask(SIG_SETMASK, &oset, NULL);
48459243Sobrien		    stderror(ERR_NOPROC);
48559243Sobrien		}
48659243Sobrien		forked++;
48759243Sobrien		if (pid) {	/* parent */
48859243Sobrien# ifdef SAVESIGVEC
48959243Sobrien		    restoresigvec(savesv, savesm);
49059243Sobrien# endif /* SAVESIGVEC */
49159243Sobrien		    child = ochild;
49259243Sobrien		    setintr = osetintr;
49359243Sobrien		    haderr = ohaderr;
49459243Sobrien		    didfds = odidfds;
49559243Sobrien		    SHIN = oSHIN;
49659243Sobrien# ifndef CLOSE_ON_EXEC
49759243Sobrien		    didcch = odidcch;
49859243Sobrien# endif /* !CLOSE_ON_EXEC */
49959243Sobrien		    SHOUT = oSHOUT;
50059243Sobrien		    SHDIAG = oSHDIAG;
50159243Sobrien		    OLDSTD = oOLDSTD;
50259243Sobrien		    tpgrp = otpgrp;
50359243Sobrien		    isoutatty = oisoutatty;
50459243Sobrien		    isdiagatty = oisdiagatty;
505167465Smp		    csigset = ocsigset;
50659243Sobrien		    nosigchld = onosigchld;
50759243Sobrien
508167465Smp		    xfree(Vsav);
50959243Sobrien		    Vsav = 0;
510167465Smp		    xfree(Vdp);
51159243Sobrien		    Vdp = 0;
512167465Smp		    xfree(Vexpath);
51359243Sobrien		    Vexpath = 0;
514167465Smp		    blk_cleanup(Vt);
51559243Sobrien		    Vt = 0;
51659243Sobrien		    /* this is from pfork() */
51759243Sobrien		    palloc(pid, t);
518167465Smp		    sigprocmask(SIG_SETMASK, &oset, NULL);
51959243Sobrien		}
52059243Sobrien		else {		/* child */
52159243Sobrien		    /* this is from pfork() */
522167465Smp		    pid_t pgrp;
523145479Smp		    int    ignint = 0;
52459243Sobrien		    if (nosigchld) {
525167465Smp			sigprocmask(SIG_SETMASK, &csigset, NULL);
52659243Sobrien			nosigchld = 0;
52759243Sobrien		    }
52859243Sobrien
52959243Sobrien		    if (setintr)
53059243Sobrien			ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
53159243Sobrien				|| (gointr && eq(gointr, STRminus));
53259243Sobrien		    pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
53359243Sobrien		    child++;
53459243Sobrien		    if (setintr) {
53559243Sobrien			setintr = 0;
53659243Sobrien/*
53759243Sobrien * casts made right for SunOS 4.0 by Douglas C. Schmidt
53859243Sobrien * <schmidt%sunshine.ics.uci.edu@ROME.ICS.UCI.EDU>
53959243Sobrien * (thanks! -- PWP)
54059243Sobrien *
54159243Sobrien * ignint ifs cleaned by Johan Widen <mcvax!osiris.sics.se!jw@uunet.UU.NET>
54259243Sobrien * (thanks again)
54359243Sobrien */
54459243Sobrien			if (ignint) {
54559243Sobrien			    (void) signal(SIGINT, SIG_IGN);
54659243Sobrien			    (void) signal(SIGQUIT, SIG_IGN);
54759243Sobrien			}
54859243Sobrien			else {
549167465Smp			    (void) signal(SIGINT, vffree);
55059243Sobrien			    (void) signal(SIGQUIT, SIG_DFL);
55159243Sobrien			}
55259243Sobrien# ifdef BSDJOBS
55359243Sobrien			if (wanttty >= 0) {
55459243Sobrien			    (void) signal(SIGTSTP, SIG_DFL);
55559243Sobrien			    (void) signal(SIGTTIN, SIG_DFL);
55659243Sobrien			    (void) signal(SIGTTOU, SIG_DFL);
55759243Sobrien			}
55859243Sobrien# endif /* BSDJOBS */
55959243Sobrien
560167465Smp			sigaction(SIGTERM, &parterm, NULL);
56159243Sobrien		    }
56259243Sobrien		    else if (tpgrp == -1 &&
56359243Sobrien			     (t->t_dflg & F_NOINTERRUPT)) {
56459243Sobrien			(void) signal(SIGINT, SIG_IGN);
56559243Sobrien			(void) signal(SIGQUIT, SIG_IGN);
56659243Sobrien		    }
56759243Sobrien
56859243Sobrien		    pgetty(wanttty, pgrp);
56959243Sobrien
57059243Sobrien		    if (t->t_dflg & F_NOHUP)
57159243Sobrien			(void) signal(SIGHUP, SIG_IGN);
57259243Sobrien		    if (t->t_dflg & F_HUP)
57359243Sobrien			(void) signal(SIGHUP, SIG_DFL);
57459243Sobrien		    if (t->t_dflg & F_NICE) {
57559243Sobrien			int nval = SIGN_EXTEND_CHAR(t->t_nice);
576316957Sdchagin# if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
57783098Smp			if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno)
57883098Smp				stderror(ERR_SYSTEM, "setpriority",
57983098Smp				    strerror(errno));
580316957Sdchagin# else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */
58159243Sobrien			(void) nice(nval);
582316957Sdchagin# endif /* HAVE_SETPRIORITY && PRIO_PROCESS */
58359243Sobrien		    }
58459243Sobrien# ifdef F_VER
58559243Sobrien		    if (t->t_dflg & F_VER) {
58659243Sobrien			tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53);
58759243Sobrien			dohash(NULL, NULL);
58859243Sobrien		    }
58959243Sobrien# endif /* F_VER */
59059243Sobrien		}
59159243Sobrien
59259243Sobrien	    }
59359243Sobrien#endif /* VFORK */
59469408Sache	}
59559243Sobrien	if (pid != 0) {
59659243Sobrien	    /*
59759243Sobrien	     * It would be better if we could wait for the whole job when we
59859243Sobrien	     * knew the last process had been started.  Pwait, in fact, does
59959243Sobrien	     * wait for the whole job anyway, but this test doesn't really
60059243Sobrien	     * express our intentions.
60159243Sobrien	     */
60259243Sobrien#ifdef BACKPIPE
60359243Sobrien	    if (didfds == 0 && t->t_dflg & F_PIPEOUT) {
604167465Smp		xclose(pipeout[0]);
605167465Smp		xclose(pipeout[1]);
60659243Sobrien	    }
60759243Sobrien	    if ((t->t_dflg & F_PIPEIN) != 0)
60859243Sobrien		break;
60959243Sobrien#else /* !BACKPIPE */
61059243Sobrien	    if (didfds == 0 && t->t_dflg & F_PIPEIN) {
611167465Smp		xclose(pipein[0]);
612167465Smp		xclose(pipein[1]);
61359243Sobrien	    }
61459243Sobrien	    if ((t->t_dflg & F_PIPEOUT) != 0)
61559243Sobrien		break;
61659243Sobrien#endif /* BACKPIPE */
61759243Sobrien
61859243Sobrien	    if (nosigchld) {
619167465Smp		sigprocmask(SIG_SETMASK, &csigset, NULL);
62059243Sobrien		nosigchld = 0;
62159243Sobrien	    }
62259243Sobrien	    if ((t->t_dflg & F_AMPERSAND) == 0)
62359243Sobrien		pwait();
62459243Sobrien	    break;
62559243Sobrien	}
62659243Sobrien
62759243Sobrien	doio(t, pipein, pipeout);
62859243Sobrien#ifdef BACKPIPE
62959243Sobrien	if (t->t_dflg & F_PIPEIN) {
630167465Smp	    xclose(pipein[0]);
631167465Smp	    xclose(pipein[1]);
63259243Sobrien	}
63359243Sobrien#else /* !BACKPIPE */
63459243Sobrien	if (t->t_dflg & F_PIPEOUT) {
635167465Smp	    xclose(pipeout[0]);
636167465Smp	    xclose(pipeout[1]);
63759243Sobrien	}
63859243Sobrien#endif /* BACKPIPE */
63959243Sobrien	/*
64059243Sobrien	 * Perform a builtin function. If we are not forked, arrange for
64159243Sobrien	 * possible stopping
64259243Sobrien	 */
64359243Sobrien	if (bifunc) {
644231990Smp	    if (forked) {
645231990Smp		func(t, bifunc);
64659243Sobrien		exitstat();
647231990Smp	    } else {
648231990Smp		jmp_buf_t oldexit;
649231990Smp		int ohaderr = haderr;
650231990Smp
651231990Smp		getexit(oldexit);
652231990Smp		if (setexit() == 0)
653231990Smp		    func(t, bifunc);
654231990Smp		resexit(oldexit);
655231990Smp		haderr = ohaderr;
656231990Smp
657145479Smp		if (adrof(STRprintexitvalue)) {
658145479Smp		    int rv = getn(varval(STRstatus));
659145479Smp		    if (rv != 0)
660145479Smp			xprintf(CGETS(17, 2, "Exit %d\n"), rv);
661145479Smp		}
662145479Smp	    }
66359243Sobrien	    break;
66459243Sobrien	}
66559243Sobrien	if (t->t_dtyp != NODE_PAREN) {
666100616Smp	    doexec(t, do_glob);
66759243Sobrien	    /* NOTREACHED */
66859243Sobrien	}
66959243Sobrien	/*
67059243Sobrien	 * For () commands must put new 0,1,2 in FSH* and recurse
67159243Sobrien	 */
672231990Smp	if ((OLDSTD = dcopy(0, FOLDSTD)) >= 0)
673231990Smp	    (void)close_on_exec(OLDSTD, 1);
674231990Smp	if ((SHOUT = dcopy(1, FSHOUT)) >= 0) {
675231990Smp	    (void)close_on_exec(SHOUT, 1);
676231990Smp	    isoutatty = isatty(SHOUT);
677231990Smp	}
678231990Smp	if ((SHDIAG = dcopy(2, FSHDIAG)) >= 0) {
679231990Smp	    (void)close_on_exec(SHDIAG, 1);
680231990Smp	    isdiagatty = isatty(SHDIAG);
681231990Smp    	}
682167465Smp	xclose(SHIN);
68359243Sobrien	SHIN = -1;
68459243Sobrien#ifndef CLOSE_ON_EXEC
68559243Sobrien	didcch = 0;
686145479Smp#else
687145479Smp	(void) close_on_exec(FSHOUT, 1);
688145479Smp	(void) close_on_exec(FSHDIAG, 1);
689145479Smp	(void) close_on_exec(FOLDSTD, 1);
69059243Sobrien#endif /* !CLOSE_ON_EXEC */
69159243Sobrien	didfds = 0;
69259243Sobrien	wanttty = -1;
693231990Smp	t->t_dspr->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
694100616Smp	execute(t->t_dspr, wanttty, NULL, NULL, do_glob);
69559243Sobrien	exitstat();
69659243Sobrien
69759243Sobrien    case NODE_PIPE:
69859243Sobrien#ifdef BACKPIPE
69959243Sobrien	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
700231990Smp	    (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ));
701100616Smp	execute(t->t_dcdr, wanttty, pv, pipeout, do_glob);
702231990Smp	t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg &
703231990Smp	    (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ));
704100616Smp	execute(t->t_dcar, wanttty, pipein, pv, do_glob);
70559243Sobrien#else /* !BACKPIPE */
706231990Smp	t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg &
707231990Smp	    (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ));
708100616Smp	execute(t->t_dcar, wanttty, pipein, pv, do_glob);
70959243Sobrien	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
710231990Smp	    (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ));
711100616Smp	execute(t->t_dcdr, wanttty, pv, pipeout, do_glob);
71259243Sobrien#endif /* BACKPIPE */
71359243Sobrien	break;
71459243Sobrien
71559243Sobrien    case NODE_LIST:
71659243Sobrien	if (t->t_dcar) {
717231990Smp	    t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
718100616Smp	    execute(t->t_dcar, wanttty, NULL, NULL, do_glob);
71959243Sobrien	    /*
72059243Sobrien	     * In strange case of A&B make a new job after A
72159243Sobrien	     */
72259243Sobrien	    if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
72359243Sobrien		(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
72459243Sobrien		pendjob();
72559243Sobrien	}
72659243Sobrien	if (t->t_dcdr) {
72759243Sobrien	    t->t_dcdr->t_dflg |= t->t_dflg &
728231990Smp		(F_NOFORK | F_NOINTERRUPT | F_BACKQ);
729100616Smp	    execute(t->t_dcdr, wanttty, NULL, NULL, do_glob);
73059243Sobrien	}
73159243Sobrien	break;
73259243Sobrien
73359243Sobrien    case NODE_OR:
73459243Sobrien    case NODE_AND:
73559243Sobrien	if (t->t_dcar) {
736231990Smp	    t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
737100616Smp	    execute(t->t_dcar, wanttty, NULL, NULL, do_glob);
73859243Sobrien	    if ((getn(varval(STRstatus)) == 0) !=
73959243Sobrien		(t->t_dtyp == NODE_AND)) {
74059243Sobrien		return;
74159243Sobrien	    }
74259243Sobrien	}
74359243Sobrien	if (t->t_dcdr) {
74459243Sobrien	    t->t_dcdr->t_dflg |= t->t_dflg &
745231990Smp		(F_NOFORK | F_NOINTERRUPT | F_BACKQ);
746100616Smp	    execute(t->t_dcdr, wanttty, NULL, NULL, do_glob);
74759243Sobrien	}
74859243Sobrien	break;
74959243Sobrien
75059243Sobrien    default:
75159243Sobrien	break;
75259243Sobrien    }
75359243Sobrien    /*
75459243Sobrien     * Fall through for all breaks from switch
75559243Sobrien     *
75659243Sobrien     * If there will be no more executions of this command, flush all file
75759243Sobrien     * descriptors. Places that turn on the F_REPEAT bit are responsible for
75859243Sobrien     * doing donefds after the last re-execution
75959243Sobrien     */
76059243Sobrien    if (didfds && !(t->t_dflg & F_REPEAT))
76159243Sobrien	donefds();
76259243Sobrien}
76359243Sobrien
76459243Sobrien#ifdef VFORK
765167465Smpstatic void
76659243Sobrien/*ARGSUSED*/
767167465Smpvffree(int snum)
76859243Sobrien{
76959243Sobrien    USE(snum);
77059243Sobrien
77159243Sobrien    _exit(1);
77259243Sobrien}
77359243Sobrien#endif /* VFORK */
77459243Sobrien
77559243Sobrien/*
77659243Sobrien * Expand and glob the words after an i/o redirection.
77759243Sobrien * If more than one word is generated, then update the command vector.
77859243Sobrien *
77959243Sobrien * This is done differently in all the shells:
78059243Sobrien * 1. in the bourne shell and ksh globbing is not performed
78159243Sobrien * 2. Bash/csh say ambiguous
78259243Sobrien * 3. zsh does i/o to/from all the files
78359243Sobrien * 4. itcsh concatenates the words.
78459243Sobrien *
78559243Sobrien * I don't know what is best to do. I think that Ambiguous is better
78659243Sobrien * than restructuring the command vector, because the user can get
78759243Sobrien * unexpected results. In any case, the command vector restructuring
78859243Sobrien * code is present and the user can choose it by setting noambiguous
78959243Sobrien */
79059243Sobrienstatic Char *
791167465Smpsplicepipe(struct command *t, Char *cp)
79259243Sobrien{
79359243Sobrien    Char *blk[2];
79459243Sobrien
79559243Sobrien    if (adrof(STRnoambiguous)) {
79659243Sobrien	Char **pv;
797167465Smp	int gflag;
79859243Sobrien
79959243Sobrien	blk[0] = Dfix1(cp); /* expand $ */
80059243Sobrien	blk[1] = NULL;
80159243Sobrien
802167465Smp	gflag = tglob(blk);
80359243Sobrien	if (gflag) {
804167465Smp	    pv = globall(blk, gflag);
80559243Sobrien	    if (pv == NULL) {
80659243Sobrien		setname(short2str(blk[0]));
807167465Smp		xfree(blk[0]);
80859243Sobrien		stderror(ERR_NAME | ERR_NOMATCH);
80959243Sobrien	    }
81059243Sobrien	    if (pv[1] != NULL) { /* we need to fix the command vector */
81159243Sobrien		Char **av = blkspl(t->t_dcom, &pv[1]);
812167465Smp		xfree(t->t_dcom);
81359243Sobrien		t->t_dcom = av;
81459243Sobrien	    }
815167465Smp	    xfree(blk[0]);
81659243Sobrien	    blk[0] = pv[0];
817167465Smp	    xfree(pv);
81859243Sobrien	}
81959243Sobrien    }
82059243Sobrien    else {
821167465Smp	Char *buf;
82259243Sobrien
823167465Smp	buf = Dfix1(cp);
824167465Smp	cleanup_push(buf, xfree);
82559243Sobrien	blk[0] = globone(buf, G_ERROR);
826167465Smp	cleanup_until(buf);
82759243Sobrien    }
82859243Sobrien    return(blk[0]);
82959243Sobrien}
83059243Sobrien
83159243Sobrien/*
83259243Sobrien * Perform io redirection.
83359243Sobrien * We may or maynot be forked here.
83459243Sobrien */
83559243Sobrienstatic void
836167465Smpdoio(struct command *t, int *pipein, int *pipeout)
83759243Sobrien{
838145479Smp    int fd;
839145479Smp    Char *cp;
840145479Smp    unsigned long flags = t->t_dflg;
84159243Sobrien
84259243Sobrien    if (didfds || (flags & F_REPEAT))
84359243Sobrien	return;
84459243Sobrien    if ((flags & F_READ) == 0) {/* F_READ already done */
84559243Sobrien	if (t->t_dlef) {
846167465Smp	    char *tmp;
84759243Sobrien
84859243Sobrien	    /*
84959243Sobrien	     * so < /dev/std{in,out,err} work
85059243Sobrien	     */
85159243Sobrien	    (void) dcopy(SHIN, 0);
85259243Sobrien	    (void) dcopy(SHOUT, 1);
85359243Sobrien	    (void) dcopy(SHDIAG, 2);
85459243Sobrien	    cp = splicepipe(t, t->t_dlef);
855167465Smp	    tmp = strsave(short2str(cp));
856167465Smp	    xfree(cp);
857167465Smp	    cleanup_push(tmp, xfree);
858167465Smp	    if ((fd = xopen(tmp, O_RDONLY|O_LARGEFILE)) < 0)
85959243Sobrien		stderror(ERR_SYSTEM, tmp, strerror(errno));
860167465Smp	    cleanup_until(tmp);
86159243Sobrien	    /* allow input files larger than 2Gb  */
862131962Smp#ifndef WINNT_NATIVE
863145479Smp	    (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_LARGEFILE);
864131962Smp#endif /*!WINNT_NATIVE*/
86559243Sobrien	    (void) dmove(fd, 0);
86659243Sobrien	}
86759243Sobrien	else if (flags & F_PIPEIN) {
868167465Smp	    xclose(0);
869231990Smp	    TCSH_IGNORE(dup(pipein[0]));
870167465Smp	    xclose(pipein[0]);
871167465Smp	    xclose(pipein[1]);
87259243Sobrien	}
87359243Sobrien	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
874167465Smp	    xclose(0);
875167465Smp	    (void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
87659243Sobrien	}
87759243Sobrien	else {
878167465Smp	    xclose(0);
879231990Smp	    TCSH_IGNORE(dup(OLDSTD));
88059243Sobrien#if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
88159243Sobrien	    /*
88259243Sobrien	     * PWP: Unlike Bezerkeley 4.3, FIONCLEX for Pyramid is preserved
88359243Sobrien	     * across dup()s, so we have to UNSET it here or else we get a
88459243Sobrien	     * command with NO stdin, stdout, or stderr at all (a bad thing
88559243Sobrien	     * indeed)
88659243Sobrien	     */
88759243Sobrien	    (void) close_on_exec(0, 0);
88859243Sobrien#endif /* CLOSE_ON_EXEC && CLEX_DUPS */
88959243Sobrien	}
89059243Sobrien    }
89159243Sobrien    if (t->t_drit) {
892167465Smp	char *tmp;
89359243Sobrien
89459243Sobrien	cp = splicepipe(t, t->t_drit);
895167465Smp	tmp = strsave(short2str(cp));
896167465Smp	xfree(cp);
897167465Smp	cleanup_push(tmp, xfree);
89859243Sobrien	/*
89959243Sobrien	 * so > /dev/std{out,err} work
90059243Sobrien	 */
90159243Sobrien	(void) dcopy(SHOUT, 1);
90259243Sobrien	(void) dcopy(SHDIAG, 2);
90359243Sobrien	if ((flags & F_APPEND) != 0) {
90459243Sobrien#ifdef O_APPEND
905167465Smp	    fd = xopen(tmp, O_WRONLY|O_APPEND|O_LARGEFILE);
90659243Sobrien#else /* !O_APPEND */
907167465Smp	    fd = xopen(tmp, O_WRONLY|O_LARGEFILE);
90859243Sobrien	    (void) lseek(fd, (off_t) 0, L_XTND);
90959243Sobrien#endif /* O_APPEND */
91059243Sobrien	}
91159243Sobrien	else
91259243Sobrien	    fd = 0;
91359243Sobrien	if ((flags & F_APPEND) == 0 || fd == -1) {
914316957Sdchagin	    if (!(flags & F_OVERWRITE) && no_clobber) {
91559243Sobrien		if (flags & F_APPEND)
91659243Sobrien		    stderror(ERR_SYSTEM, tmp, strerror(errno));
91759243Sobrien		chkclob(tmp);
91859243Sobrien	    }
919167465Smp	    if ((fd = xcreat(tmp, 0666)) < 0)
92059243Sobrien		stderror(ERR_SYSTEM, tmp, strerror(errno));
92159243Sobrien	    /* allow input files larger than 2Gb  */
922131962Smp#ifndef WINNT_NATIVE
923145479Smp	    (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_LARGEFILE);
924131962Smp#endif /*!WINNT_NATIVE*/
92559243Sobrien	}
926167465Smp	cleanup_until(tmp);
92759243Sobrien	(void) dmove(fd, 1);
92859243Sobrien	is1atty = isatty(1);
92959243Sobrien    }
93059243Sobrien    else if (flags & F_PIPEOUT) {
931167465Smp	xclose(1);
932231990Smp	TCSH_IGNORE(dup(pipeout[1]));
93359243Sobrien	is1atty = 0;
93459243Sobrien    }
93559243Sobrien    else {
936167465Smp	xclose(1);
937231990Smp	TCSH_IGNORE(dup(SHOUT));
93859243Sobrien	is1atty = isoutatty;
93959243Sobrien# if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
94059243Sobrien	(void) close_on_exec(1, 0);
94159243Sobrien# endif /* CLOSE_ON_EXEC && CLEX_DUPS */
94259243Sobrien    }
94359243Sobrien
944167465Smp    xclose(2);
94559243Sobrien    if (flags & F_STDERR) {
946231990Smp	TCSH_IGNORE(dup(1));
94759243Sobrien	is2atty = is1atty;
94859243Sobrien    }
94959243Sobrien    else {
950231990Smp	TCSH_IGNORE(dup(SHDIAG));
95159243Sobrien	is2atty = isdiagatty;
95259243Sobrien# if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
95359243Sobrien	(void) close_on_exec(2, 0);
95459243Sobrien# endif /* CLOSE_ON_EXEC && CLEX_DUPS */
95559243Sobrien    }
95659243Sobrien    didfds = 1;
95759243Sobrien}
95859243Sobrien
95959243Sobrienvoid
960167465Smpmypipe(int *pv)
96159243Sobrien{
96259243Sobrien
96359243Sobrien    if (pipe(pv) < 0)
96459243Sobrien	goto oops;
965145479Smp    (void)close_on_exec(pv[0] = dmove(pv[0], -1), 1);
966145479Smp    (void)close_on_exec(pv[1] = dmove(pv[1], -1), 1);
96759243Sobrien    if (pv[0] >= 0 && pv[1] >= 0)
96859243Sobrien	return;
969167465Smp    if (pv[0] >= 0)
970167465Smp	xclose(pv[0]);
971167465Smp    if (pv[1] >= 0)
972167465Smp	xclose(pv[1]);
97359243Sobrienoops:
97459243Sobrien    stderror(ERR_PIPE);
97559243Sobrien}
97659243Sobrien
97759243Sobrienstatic void
978167465Smpchkclob(const 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;
986316957Sdchagin    if (no_clobber & NOCLOBBER_NOTEMPTY && stb.st_size == 0)
987316957Sdchagin	return;
988316957Sdchagin    if (no_clobber & NOCLOBBER_ASK) {
989316957Sdchagin	if (getYN(CGETS(22, 15,
990316957Sdchagin	    "Do you really want to overwrite an existing file? [N/y] ")))
991316957Sdchagin	    return;
992316957Sdchagin    }
993316957Sdchagin
99459243Sobrien    stderror(ERR_EXISTS, cp);
99559243Sobrien}
996