PageRenderTime 126ms CodeModel.GetById 64ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/tcsh/sh.sem.c

https://bitbucket.org/freebsd/freebsd-head/
C | 974 lines | 716 code | 63 blank | 195 comment | 255 complexity | 121086f6ba8f4de4e88f5f1409c125ba MD5 | raw file
  1/* $Header: /p/tcsh/cvsroot/tcsh/sh.sem.c,v 3.86 2011/02/25 23:24:19 christos Exp $ */
  2/*
  3 * sh.sem.c: I/O redirections and job forking. A touchy issue!
  4 *	     Most stuff with builtins is incorrect
  5 */
  6/*-
  7 * Copyright (c) 1980, 1991 The Regents of the University of California.
  8 * All rights reserved.
  9 *
 10 * Redistribution and use in source and binary forms, with or without
 11 * modification, are permitted provided that the following conditions
 12 * are met:
 13 * 1. Redistributions of source code must retain the above copyright
 14 *    notice, this list of conditions and the following disclaimer.
 15 * 2. Redistributions in binary form must reproduce the above copyright
 16 *    notice, this list of conditions and the following disclaimer in the
 17 *    documentation and/or other materials provided with the distribution.
 18 * 3. Neither the name of the University nor the names of its contributors
 19 *    may be used to endorse or promote products derived from this software
 20 *    without specific prior written permission.
 21 *
 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 32 * SUCH DAMAGE.
 33 */
 34#include "sh.h"
 35
 36RCSID("$tcsh: sh.sem.c,v 3.86 2011/02/25 23:24:19 christos Exp $")
 37
 38#include "tc.h"
 39#include "tw.h"
 40#ifdef WINNT_NATIVE
 41#include "nt.const.h"
 42#endif /*WINNT_NATIVE*/
 43
 44#ifdef CLOSE_ON_EXEC
 45# ifndef SUNOS4
 46#  ifndef CLEX_DUPS
 47#   define CLEX_DUPS
 48#  endif /* CLEX_DUPS */
 49# endif /* !SUNOS4 */
 50#endif /* CLOSE_ON_EXEC */
 51
 52#if defined(__sparc__) || defined(sparc)
 53# if !defined(MACH) && SYSVREL == 0 && !defined(Lynx) && !defined(BSD4_4) && !defined(__linux__) && !defined(__GNU__) && !defined(__GLIBC__)
 54#  include <vfork.h>
 55# endif /* !MACH && SYSVREL == 0 && !Lynx && !BSD4_4 && !glibc */
 56#endif /* __sparc__ || sparc */
 57
 58#ifdef VFORK
 59static	void		vffree		(int);
 60#endif 
 61static	Char		*splicepipe	(struct command *, Char *);
 62static	void		 doio		(struct command *, int *, int *);
 63static	void		 chkclob	(const char *);
 64
 65/*
 66 * C shell
 67 */
 68
 69/*
 70 * For SVR4, there are problems with pipelines having the first process as
 71 * the group leader.  The problem occurs when the first process exits before
 72 * the others have a chance to setpgid().  This is because in SVR4 you can't
 73 * have a zombie as a group leader.  The solution I have used is to reverse
 74 * the order in which pipelines are started, making the last process the
 75 * group leader.  (Note I am not using 'pipeline' in the generic sense -- I
 76 * mean processes connected by '|'.)  I don't know yet if this causes other
 77 * problems.
 78 *
 79 * All the changes for this are in execute(), and are enclosed in 
 80 * '#ifdef BACKPIPE'
 81 *
 82 * David Dawes (dawes@physics.su.oz.au) Oct 1991
 83 */
 84
 85/*VARARGS 1*/
 86void
 87execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout,
 88    int do_glob)
 89{
 90    int    forked = 0;
 91    const struct biltins * volatile bifunc;
 92    pid_t pid = 0;
 93    int     pv[2];
 94    sigset_t set;
 95    static sigset_t csigset;
 96#ifdef VFORK
 97    static int onosigchld = 0;
 98#endif /* VFORK */
 99    static int nosigchld = 0;
100
101    (void) &wanttty;
102    (void) &forked;
103    (void) &bifunc;
104
105    if (t == 0) 
106	return;
107
108#ifdef WINNT_NATIVE
109    {
110        if ((varval(STRNTslowexec) == STRNULL) &&
111            !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds &&
112            (intty || intact) && (t->t_dtyp == NODE_COMMAND) &&
113	    !isbfunc(t)) {
114	    if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
115		(void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
116	    Dfix(t);
117            if (nt_try_fast_exec(t) == 0)
118                return;
119        }
120    }
121#endif /* WINNT_NATIVE */
122
123    /*
124     * Ed hutchins@sgi.com & Dominic dbg@sgi.com
125     * Sat Feb 25 03:13:11 PST 1995
126     * try implicit cd if we have a 1 word command 
127     */
128    if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] &&
129	 t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) {
130	Char *sCName;
131	struct stat stbuf;
132	char *pathname;
133
134	sCName = dollar(t->t_dcom[0]);
135	if (sCName != NULL && sCName[0] == '~') {
136	    struct Strbuf buf = Strbuf_INIT;
137	    const Char *name_end;
138
139	    for (name_end = sCName + 1; *name_end != '\0' && *name_end != '/';
140		 name_end++)
141		continue;
142	    if (name_end != sCName + 1) {
143		Char *name, *home;
144
145		name = Strnsave(sCName + 1, name_end - (sCName + 1));
146		home = gethdir(name);
147		if (home != NULL) {
148		    Strbuf_append(&buf, home);
149		    xfree(home);
150		} else
151		    Strbuf_append(&buf, name);
152		xfree(name);
153	    } else
154		Strbuf_append(&buf, varval(STRhome));
155	    Strbuf_append(&buf, name_end);
156	    xfree(sCName);
157	    sCName = Strbuf_finish(&buf);
158	}
159
160	pathname = short2str(sCName);
161	xfree(sCName);
162	/* if this is a dir, tack a "cd" on as the first arg */
163	if (pathname != NULL &&
164	    ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode))
165#ifdef WINNT_NATIVE
166	     || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0')
167#endif /* WINNT_NATIVE */
168	     )) {
169	    Char *vCD[2];
170	    Char **ot_dcom = t->t_dcom;
171	
172	    vCD[0] = Strsave(STRcd);
173	    vCD[1] = NULL;
174	    t->t_dcom = blkspl(vCD, ot_dcom);
175	    xfree(ot_dcom);
176	    if (implicit_cd > 1) {
177		blkpr(t->t_dcom);
178		xputchar( '\n' );
179	    }
180	}
181    }
182
183    /*
184     * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
185     * Don't check for wantty > 0...
186     */
187    if (t->t_dflg & F_AMPERSAND)
188	wanttty = 0;
189    switch (t->t_dtyp) {
190
191    case NODE_COMMAND:
192	if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
193	    memmove(t->t_dcom[0], t->t_dcom[0] + 1,
194		    (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0]));
195	if ((t->t_dflg & F_REPEAT) == 0)
196	    Dfix(t);		/* $ " ' \ */
197	if (t->t_dcom[0] == 0) {
198	    return;
199	}
200	/*FALLTHROUGH*/
201
202    case NODE_PAREN:
203#ifdef BACKPIPE
204	if (t->t_dflg & F_PIPEIN)
205	    mypipe(pipein);
206#else /* !BACKPIPE */
207	if (t->t_dflg & F_PIPEOUT)
208	    mypipe(pipeout);
209#endif /* BACKPIPE */
210	/*
211	 * Must do << early so parent will know where input pointer should be.
212	 * If noexec then this is all we do.
213	 */
214	if (t->t_dflg & F_READ) {
215	    xclose(0);
216	    heredoc(t->t_dlef);
217	    if (noexec)
218		xclose(0);
219	}
220
221	setcopy(STRstatus, STR0, VAR_READWRITE);
222
223	/*
224	 * This mess is the necessary kludge to handle the prefix builtins:
225	 * nice, nohup, time.  These commands can also be used by themselves,
226	 * and this is not handled here. This will also work when loops are
227	 * parsed.
228	 */
229	while (t->t_dtyp == NODE_COMMAND)
230	    if (eq(t->t_dcom[0], STRnice)) {
231		if (t->t_dcom[1]) {
232		    if (strchr("+-", t->t_dcom[1][0])) {
233			if (t->t_dcom[2]) {
234			    setname("nice");
235			    t->t_nice = (unsigned char)getn(t->t_dcom[1]);
236			    lshift(t->t_dcom, 2);
237			    t->t_dflg |= F_NICE;
238			}
239			else
240			    break;
241		    }
242		    else {
243			t->t_nice = 4;
244			lshift(t->t_dcom, 1);
245			t->t_dflg |= F_NICE;
246		    }
247		}
248		else
249		    break;
250	    }
251	    else if (eq(t->t_dcom[0], STRnohup)) {
252		if (t->t_dcom[1]) {
253		    t->t_dflg |= F_NOHUP;
254		    lshift(t->t_dcom, 1);
255		}
256		else
257		    break;
258	    }
259	    else if (eq(t->t_dcom[0], STRhup)) {
260		if (t->t_dcom[1]) {
261		    t->t_dflg |= F_HUP;
262		    lshift(t->t_dcom, 1);
263		}
264		else
265		    break;
266	    }
267	    else if (eq(t->t_dcom[0], STRtime)) {
268		if (t->t_dcom[1]) {
269		    t->t_dflg |= F_TIME;
270		    lshift(t->t_dcom, 1);
271		}
272		else
273		    break;
274	    }
275#ifdef F_VER
276	    else if (eq(t->t_dcom[0], STRver))
277		if (t->t_dcom[1] && t->t_dcom[2]) {
278		    setname("ver");
279		    t->t_systype = getv(t->t_dcom[1]);
280		    lshift(t->t_dcom, 2);
281		    t->t_dflg |= F_VER;
282		}
283		else
284		    break;
285#endif  /* F_VER */
286	    else
287		break;
288
289	/* is it a command */
290	if (t->t_dtyp == NODE_COMMAND) {
291	    /*
292	     * Check if we have a builtin function and remember which one.
293	     */
294	    bifunc = isbfunc(t);
295 	    if (noexec) {
296		/*
297		 * Continue for builtins that are part of the scripting language
298		 */
299		if (bifunc == NULL)
300		    break;
301		if (bifunc->bfunct != (bfunc_t)dobreak	&&
302		    bifunc->bfunct != (bfunc_t)docontin	&&
303		    bifunc->bfunct != (bfunc_t)doelse	&&
304		    bifunc->bfunct != (bfunc_t)doend	&&
305		    bifunc->bfunct != (bfunc_t)doforeach&&
306		    bifunc->bfunct != (bfunc_t)dogoto	&&
307		    bifunc->bfunct != (bfunc_t)doif	&&
308		    bifunc->bfunct != (bfunc_t)dorepeat	&&
309		    bifunc->bfunct != (bfunc_t)doswbrk	&&
310		    bifunc->bfunct != (bfunc_t)doswitch	&&
311		    bifunc->bfunct != (bfunc_t)dowhile	&&
312		    bifunc->bfunct != (bfunc_t)dozip)
313		    break;
314	    }
315	}
316	else {			/* not a command */
317	    bifunc = NULL;
318	    if (noexec)
319		break;
320	}
321
322	/* 
323	 * GrP Executing a command - run jobcmd hook
324	 * Don't run for builtins
325	 * Don't run if we're not in a tty
326	 * Don't run if we're not really executing 
327	 */
328	/*
329	 * CR  -  Charles Ross Aug 2005
330	 * added "isoutatty".
331	 * The new behavior is that the jobcmd won't be executed
332	 * if stdout (SHOUT) isnt attached to a tty.. IE when
333	 * redirecting, or using backquotes etc..
334	 */
335	if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty && isoutatty) {
336	    Char *cmd = unparse(t);
337
338	    cleanup_push(cmd, xfree);
339	    job_cmd(cmd);
340	    cleanup_until(cmd);
341	}
342	   
343	/*
344	 * We fork only if we are timed, or are not the end of a parenthesized
345	 * list and not a simple builtin function. Simple meaning one that is
346	 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
347	 * fork in some of these cases.
348	 */
349	/*
350	 * Prevent forking cd, pushd, popd, chdir cause this will cause the
351	 * shell not to change dir!
352	 */
353#ifdef BACKPIPE
354	/*
355	 * Can't have NOFORK for the tail of a pipe - because it is not the
356	 * last command spawned (even if it is at the end of a parenthesised
357	 * list).
358	 */
359	if (t->t_dflg & F_PIPEIN)
360	    t->t_dflg &= ~(F_NOFORK);
361#endif /* BACKPIPE */
362	if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd ||
363		       bifunc->bfunct == (bfunc_t)dopushd ||
364		       bifunc->bfunct == (bfunc_t)dopopd))
365	    t->t_dflg &= ~(F_NICE);
366	if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
367	     (!bifunc || t->t_dflg &
368	      (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) ||
369	/*
370	 * We have to fork for eval too.
371	 */
372	    (bifunc && (t->t_dflg & F_PIPEIN) != 0 &&
373	     bifunc->bfunct == (bfunc_t)doeval)) {
374#ifdef VFORK
375	    if (t->t_dtyp == NODE_PAREN ||
376		t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc)
377#endif /* VFORK */
378	    {
379		forked++;
380		/*
381		 * We need to block SIGCHLD here, so that if the process does
382		 * not die before we can set the process group
383		 */
384		if (wanttty >= 0 && !nosigchld) {
385		    sigemptyset(&set);
386		    sigaddset(&set, SIGCHLD);
387		    (void)sigprocmask(SIG_BLOCK, &set, &csigset);
388
389		    nosigchld = 1;
390		}
391
392		pid = pfork(t, wanttty);
393		if (pid == 0 && nosigchld) {
394		    sigprocmask(SIG_SETMASK, &csigset, NULL);
395		    nosigchld = 0;
396		}
397		else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
398		    backpid = pid;
399	    }
400
401#ifdef VFORK
402	    else {
403		int     ochild, osetintr, ohaderr, odidfds;
404		int     oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
405		int     oisoutatty, oisdiagatty;
406		sigset_t oset, ocsigset;
407# ifndef CLOSE_ON_EXEC
408		int     odidcch;
409# endif  /* !CLOSE_ON_EXEC */
410
411		/*
412		 * Prepare for the vfork by saving everything that the child
413		 * corrupts before it exec's. Note that in some signal
414		 * implementations which keep the signal info in user space
415		 * (e.g. Sun's) it will also be necessary to save and restore
416		 * the current sigvec's for the signals the child touches
417		 * before it exec's.
418		 */
419
420		/*
421		 * Sooooo true... If this is a Sun, save the sigvec's. (Skip
422		 * Gilbrech - 11/22/87)
423		 */
424# ifdef SAVESIGVEC
425		struct sigaction savesv[NSIGSAVED];
426		sigset_t savesm;
427
428# endif /* SAVESIGVEC */
429		if (wanttty >= 0 && !nosigchld && !noexec) {
430		    sigemptyset(&set);
431		    sigaddset(&set, SIGCHLD);
432		    (void)sigprocmask(SIG_BLOCK, &set, &csigset);
433		    nosigchld = 1;
434		}
435		sigemptyset(&set);
436		sigaddset(&set, SIGCHLD);
437		sigaddset(&set, SIGINT);
438		(void)sigprocmask(SIG_BLOCK, &set, &oset);
439		ochild = child;
440		osetintr = setintr;
441		ohaderr = haderr;
442		odidfds = didfds;
443# ifndef CLOSE_ON_EXEC
444		odidcch = didcch;
445# endif /* !CLOSE_ON_EXEC */
446		oSHIN = SHIN;
447		oSHOUT = SHOUT;
448		oSHDIAG = SHDIAG;
449		oOLDSTD = OLDSTD;
450		otpgrp = tpgrp;
451		oisoutatty = isoutatty;
452		oisdiagatty = isdiagatty;
453		ocsigset = csigset;
454		onosigchld = nosigchld;
455		Vsav = Vdp = 0;
456		Vexpath = 0;
457		Vt = 0;
458# ifdef SAVESIGVEC
459		savesigvec(savesv, savesm);
460# endif /* SAVESIGVEC */
461		if (use_fork)
462		    pid = fork();
463		else
464		    pid = vfork();
465
466		if (pid < 0) {
467# ifdef SAVESIGVEC
468		    restoresigvec(savesv, savesm);
469# endif /* SAVESIGVEC */
470		    sigprocmask(SIG_SETMASK, &oset, NULL);
471		    stderror(ERR_NOPROC);
472		}
473		forked++;
474		if (pid) {	/* parent */
475# ifdef SAVESIGVEC
476		    restoresigvec(savesv, savesm);
477# endif /* SAVESIGVEC */
478		    child = ochild;
479		    setintr = osetintr;
480		    haderr = ohaderr;
481		    didfds = odidfds;
482		    SHIN = oSHIN;
483# ifndef CLOSE_ON_EXEC
484		    didcch = odidcch;
485# endif /* !CLOSE_ON_EXEC */
486		    SHOUT = oSHOUT;
487		    SHDIAG = oSHDIAG;
488		    OLDSTD = oOLDSTD;
489		    tpgrp = otpgrp;
490		    isoutatty = oisoutatty;
491		    isdiagatty = oisdiagatty;
492		    csigset = ocsigset;
493		    nosigchld = onosigchld;
494
495		    xfree(Vsav);
496		    Vsav = 0;
497		    xfree(Vdp);
498		    Vdp = 0;
499		    xfree(Vexpath);
500		    Vexpath = 0;
501		    blk_cleanup(Vt);
502		    Vt = 0;
503		    /* this is from pfork() */
504		    palloc(pid, t);
505		    sigprocmask(SIG_SETMASK, &oset, NULL);
506		}
507		else {		/* child */
508		    /* this is from pfork() */
509		    pid_t pgrp;
510		    int    ignint = 0;
511		    if (nosigchld) {
512			sigprocmask(SIG_SETMASK, &csigset, NULL);
513			nosigchld = 0;
514		    }
515
516		    if (setintr)
517			ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
518				|| (gointr && eq(gointr, STRminus));
519		    pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
520		    child++;
521		    if (setintr) {
522			setintr = 0;
523/*
524 * casts made right for SunOS 4.0 by Douglas C. Schmidt
525 * <schmidt%sunshine.ics.uci.edu@ROME.ICS.UCI.EDU>
526 * (thanks! -- PWP)
527 *
528 * ignint ifs cleaned by Johan Widen <mcvax!osiris.sics.se!jw@uunet.UU.NET>
529 * (thanks again)
530 */
531			if (ignint) {
532			    (void) signal(SIGINT, SIG_IGN);
533			    (void) signal(SIGQUIT, SIG_IGN);
534			}
535			else {
536			    (void) signal(SIGINT, vffree);
537			    (void) signal(SIGQUIT, SIG_DFL);
538			}
539# ifdef BSDJOBS
540			if (wanttty >= 0) {
541			    (void) signal(SIGTSTP, SIG_DFL);
542			    (void) signal(SIGTTIN, SIG_DFL);
543			    (void) signal(SIGTTOU, SIG_DFL);
544			}
545# endif /* BSDJOBS */
546
547			sigaction(SIGTERM, &parterm, NULL);
548		    }
549		    else if (tpgrp == -1 &&
550			     (t->t_dflg & F_NOINTERRUPT)) {
551			(void) signal(SIGINT, SIG_IGN);
552			(void) signal(SIGQUIT, SIG_IGN);
553		    }
554
555		    pgetty(wanttty, pgrp);
556
557		    if (t->t_dflg & F_NOHUP)
558			(void) signal(SIGHUP, SIG_IGN);
559		    if (t->t_dflg & F_HUP)
560			(void) signal(SIGHUP, SIG_DFL);
561		    if (t->t_dflg & F_NICE) {
562			int nval = SIGN_EXTEND_CHAR(t->t_nice);
563# ifdef HAVE_SETPRIORITY
564			if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno)
565				stderror(ERR_SYSTEM, "setpriority",
566				    strerror(errno));
567# else /* !HAVE_SETPRIORITY */
568			(void) nice(nval);
569# endif /* HAVE_SETPRIORITY */
570		    }
571# ifdef F_VER
572		    if (t->t_dflg & F_VER) {
573			tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53);
574			dohash(NULL, NULL);
575		    }
576# endif /* F_VER */
577		}
578
579	    }
580#endif /* VFORK */
581	}
582	if (pid != 0) {
583	    /*
584	     * It would be better if we could wait for the whole job when we
585	     * knew the last process had been started.  Pwait, in fact, does
586	     * wait for the whole job anyway, but this test doesn't really
587	     * express our intentions.
588	     */
589#ifdef BACKPIPE
590	    if (didfds == 0 && t->t_dflg & F_PIPEOUT) {
591		xclose(pipeout[0]);
592		xclose(pipeout[1]);
593	    }
594	    if ((t->t_dflg & F_PIPEIN) != 0)
595		break;
596#else /* !BACKPIPE */
597	    if (didfds == 0 && t->t_dflg & F_PIPEIN) {
598		xclose(pipein[0]);
599		xclose(pipein[1]);
600	    }
601	    if ((t->t_dflg & F_PIPEOUT) != 0)
602		break;
603#endif /* BACKPIPE */
604
605	    if (nosigchld) {
606		sigprocmask(SIG_SETMASK, &csigset, NULL);
607		nosigchld = 0;
608	    }
609	    if ((t->t_dflg & F_AMPERSAND) == 0)
610		pwait();
611	    break;
612	}
613
614	doio(t, pipein, pipeout);
615#ifdef BACKPIPE
616	if (t->t_dflg & F_PIPEIN) {
617	    xclose(pipein[0]);
618	    xclose(pipein[1]);
619	}
620#else /* !BACKPIPE */
621	if (t->t_dflg & F_PIPEOUT) {
622	    xclose(pipeout[0]);
623	    xclose(pipeout[1]);
624	}
625#endif /* BACKPIPE */
626	/*
627	 * Perform a builtin function. If we are not forked, arrange for
628	 * possible stopping
629	 */
630	if (bifunc) {
631	    if (forked) {
632		func(t, bifunc);
633		exitstat();
634	    } else {
635		jmp_buf_t oldexit;
636		int ohaderr = haderr;
637
638		getexit(oldexit);
639		if (setexit() == 0)
640		    func(t, bifunc);
641		resexit(oldexit);
642		haderr = ohaderr;
643
644		if (adrof(STRprintexitvalue)) {
645		    int rv = getn(varval(STRstatus));
646		    if (rv != 0)
647			xprintf(CGETS(17, 2, "Exit %d\n"), rv);
648		}
649	    }
650	    break;
651	}
652	if (t->t_dtyp != NODE_PAREN) {
653	    doexec(t, do_glob);
654	    /* NOTREACHED */
655	}
656	/*
657	 * For () commands must put new 0,1,2 in FSH* and recurse
658	 */
659	if ((OLDSTD = dcopy(0, FOLDSTD)) >= 0)
660	    (void)close_on_exec(OLDSTD, 1);
661	if ((SHOUT = dcopy(1, FSHOUT)) >= 0) {
662	    (void)close_on_exec(SHOUT, 1);
663	    isoutatty = isatty(SHOUT);
664	}
665	if ((SHDIAG = dcopy(2, FSHDIAG)) >= 0) {
666	    (void)close_on_exec(SHDIAG, 1);
667	    isdiagatty = isatty(SHDIAG);
668    	}
669	xclose(SHIN);
670	SHIN = -1;
671#ifndef CLOSE_ON_EXEC
672	didcch = 0;
673#else
674	(void) close_on_exec(FSHOUT, 1);
675	(void) close_on_exec(FSHDIAG, 1);
676	(void) close_on_exec(FOLDSTD, 1);
677#endif /* !CLOSE_ON_EXEC */
678	didfds = 0;
679	wanttty = -1;
680	t->t_dspr->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
681	execute(t->t_dspr, wanttty, NULL, NULL, do_glob);
682	exitstat();
683
684    case NODE_PIPE:
685#ifdef BACKPIPE
686	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
687	    (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ));
688	execute(t->t_dcdr, wanttty, pv, pipeout, do_glob);
689	t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg &
690	    (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ));
691	execute(t->t_dcar, wanttty, pipein, pv, do_glob);
692#else /* !BACKPIPE */
693	t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg &
694	    (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ));
695	execute(t->t_dcar, wanttty, pipein, pv, do_glob);
696	t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
697	    (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ));
698	execute(t->t_dcdr, wanttty, pv, pipeout, do_glob);
699#endif /* BACKPIPE */
700	break;
701
702    case NODE_LIST:
703	if (t->t_dcar) {
704	    t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
705	    execute(t->t_dcar, wanttty, NULL, NULL, do_glob);
706	    /*
707	     * In strange case of A&B make a new job after A
708	     */
709	    if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
710		(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
711		pendjob();
712	}
713	if (t->t_dcdr) {
714	    t->t_dcdr->t_dflg |= t->t_dflg &
715		(F_NOFORK | F_NOINTERRUPT | F_BACKQ);
716	    execute(t->t_dcdr, wanttty, NULL, NULL, do_glob);
717	}
718	break;
719
720    case NODE_OR:
721    case NODE_AND:
722	if (t->t_dcar) {
723	    t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ);
724	    execute(t->t_dcar, wanttty, NULL, NULL, do_glob);
725	    if ((getn(varval(STRstatus)) == 0) !=
726		(t->t_dtyp == NODE_AND)) {
727		return;
728	    }
729	}
730	if (t->t_dcdr) {
731	    t->t_dcdr->t_dflg |= t->t_dflg &
732		(F_NOFORK | F_NOINTERRUPT | F_BACKQ);
733	    execute(t->t_dcdr, wanttty, NULL, NULL, do_glob);
734	}
735	break;
736
737    default:
738	break;
739    }
740    /*
741     * Fall through for all breaks from switch
742     * 
743     * If there will be no more executions of this command, flush all file
744     * descriptors. Places that turn on the F_REPEAT bit are responsible for
745     * doing donefds after the last re-execution
746     */
747    if (didfds && !(t->t_dflg & F_REPEAT))
748	donefds();
749}
750
751#ifdef VFORK
752static void
753/*ARGSUSED*/
754vffree(int snum)
755{
756    USE(snum);
757
758    _exit(1);
759}
760#endif /* VFORK */
761
762/*
763 * Expand and glob the words after an i/o redirection.
764 * If more than one word is generated, then update the command vector.
765 *
766 * This is done differently in all the shells:
767 * 1. in the bourne shell and ksh globbing is not performed
768 * 2. Bash/csh say ambiguous
769 * 3. zsh does i/o to/from all the files
770 * 4. itcsh concatenates the words.
771 *
772 * I don't know what is best to do. I think that Ambiguous is better
773 * than restructuring the command vector, because the user can get
774 * unexpected results. In any case, the command vector restructuring 
775 * code is present and the user can choose it by setting noambiguous
776 */
777static Char *
778splicepipe(struct command *t, Char *cp)
779{
780    Char *blk[2];
781
782    if (adrof(STRnoambiguous)) {
783	Char **pv;
784	int gflag;
785
786	blk[0] = Dfix1(cp); /* expand $ */
787	blk[1] = NULL;
788
789	gflag = tglob(blk);
790	if (gflag) {
791	    pv = globall(blk, gflag);
792	    if (pv == NULL) {
793		setname(short2str(blk[0]));
794		xfree(blk[0]);
795		stderror(ERR_NAME | ERR_NOMATCH);
796	    }
797	    if (pv[1] != NULL) { /* we need to fix the command vector */
798		Char **av = blkspl(t->t_dcom, &pv[1]);
799		xfree(t->t_dcom);
800		t->t_dcom = av;
801	    }
802	    xfree(blk[0]);
803	    blk[0] = pv[0];
804	    xfree(pv);
805	}
806    }
807    else {
808	Char *buf;
809
810	buf = Dfix1(cp);
811	cleanup_push(buf, xfree);
812	blk[0] = globone(buf, G_ERROR);
813	cleanup_until(buf);
814    }
815    return(blk[0]);
816}
817    
818/*
819 * Perform io redirection.
820 * We may or maynot be forked here.
821 */
822static void
823doio(struct command *t, int *pipein, int *pipeout)
824{
825    int fd;
826    Char *cp;
827    unsigned long flags = t->t_dflg;
828
829    if (didfds || (flags & F_REPEAT))
830	return;
831    if ((flags & F_READ) == 0) {/* F_READ already done */
832	if (t->t_dlef) {
833	    char *tmp;
834
835	    /*
836	     * so < /dev/std{in,out,err} work
837	     */
838	    (void) dcopy(SHIN, 0);
839	    (void) dcopy(SHOUT, 1);
840	    (void) dcopy(SHDIAG, 2);
841	    cp = splicepipe(t, t->t_dlef);
842	    tmp = strsave(short2str(cp));
843	    xfree(cp);
844	    cleanup_push(tmp, xfree);
845	    if ((fd = xopen(tmp, O_RDONLY|O_LARGEFILE)) < 0)
846		stderror(ERR_SYSTEM, tmp, strerror(errno));
847	    cleanup_until(tmp);
848	    /* allow input files larger than 2Gb  */
849#ifndef WINNT_NATIVE
850	    (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_LARGEFILE);
851#endif /*!WINNT_NATIVE*/
852	    (void) dmove(fd, 0);
853	}
854	else if (flags & F_PIPEIN) {
855	    xclose(0);
856	    TCSH_IGNORE(dup(pipein[0]));
857	    xclose(pipein[0]);
858	    xclose(pipein[1]);
859	}
860	else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
861	    xclose(0);
862	    (void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
863	}
864	else {
865	    xclose(0);
866	    TCSH_IGNORE(dup(OLDSTD));
867#if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
868	    /*
869	     * PWP: Unlike Bezerkeley 4.3, FIONCLEX for Pyramid is preserved
870	     * across dup()s, so we have to UNSET it here or else we get a
871	     * command with NO stdin, stdout, or stderr at all (a bad thing
872	     * indeed)
873	     */
874	    (void) close_on_exec(0, 0);
875#endif /* CLOSE_ON_EXEC && CLEX_DUPS */
876	}
877    }
878    if (t->t_drit) {
879	char *tmp;
880
881	cp = splicepipe(t, t->t_drit);
882	tmp = strsave(short2str(cp));
883	xfree(cp);
884	cleanup_push(tmp, xfree);
885	/*
886	 * so > /dev/std{out,err} work
887	 */
888	(void) dcopy(SHOUT, 1);
889	(void) dcopy(SHDIAG, 2);
890	if ((flags & F_APPEND) != 0) {
891#ifdef O_APPEND
892	    fd = xopen(tmp, O_WRONLY|O_APPEND|O_LARGEFILE);
893#else /* !O_APPEND */
894	    fd = xopen(tmp, O_WRONLY|O_LARGEFILE);
895	    (void) lseek(fd, (off_t) 0, L_XTND);
896#endif /* O_APPEND */
897	}
898	else
899	    fd = 0;
900	if ((flags & F_APPEND) == 0 || fd == -1) {
901	    if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
902		if (flags & F_APPEND)
903		    stderror(ERR_SYSTEM, tmp, strerror(errno));
904		chkclob(tmp);
905	    }
906	    if ((fd = xcreat(tmp, 0666)) < 0)
907		stderror(ERR_SYSTEM, tmp, strerror(errno));
908	    /* allow input files larger than 2Gb  */
909#ifndef WINNT_NATIVE
910	    (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_LARGEFILE);
911#endif /*!WINNT_NATIVE*/
912	}
913	cleanup_until(tmp);
914	(void) dmove(fd, 1);
915	is1atty = isatty(1);
916    }
917    else if (flags & F_PIPEOUT) {
918	xclose(1);
919	TCSH_IGNORE(dup(pipeout[1]));
920	is1atty = 0;
921    }
922    else {
923	xclose(1);
924	TCSH_IGNORE(dup(SHOUT));
925	is1atty = isoutatty;
926# if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
927	(void) close_on_exec(1, 0);
928# endif /* CLOSE_ON_EXEC && CLEX_DUPS */
929    }
930
931    xclose(2);
932    if (flags & F_STDERR) {
933	TCSH_IGNORE(dup(1));
934	is2atty = is1atty;
935    }
936    else {
937	TCSH_IGNORE(dup(SHDIAG));
938	is2atty = isdiagatty;
939# if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS)
940	(void) close_on_exec(2, 0);
941# endif /* CLOSE_ON_EXEC && CLEX_DUPS */
942    }
943    didfds = 1;
944}
945
946void
947mypipe(int *pv)
948{
949
950    if (pipe(pv) < 0)
951	goto oops;
952    (void)close_on_exec(pv[0] = dmove(pv[0], -1), 1);
953    (void)close_on_exec(pv[1] = dmove(pv[1], -1), 1);
954    if (pv[0] >= 0 && pv[1] >= 0)
955	return;
956    if (pv[0] >= 0)
957	xclose(pv[0]);
958    if (pv[1] >= 0)
959	xclose(pv[1]);
960oops:
961    stderror(ERR_PIPE);
962}
963
964static void
965chkclob(const char *cp)
966{
967    struct stat stb;
968
969    if (stat(cp, &stb) < 0)
970	return;
971    if (S_ISCHR(stb.st_mode))
972	return;
973    stderror(ERR_EXISTS, cp);
974}