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