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