1*19d2e3deSDmitry Chagin /* $Header: /p/tcsh/cvsroot/tcsh/sh.sem.c,v 3.90 2015/10/31 18:54:42 christos Exp $ */ 2c80476e4SDavid E. O'Brien /* 3c80476e4SDavid E. O'Brien * sh.sem.c: I/O redirections and job forking. A touchy issue! 4c80476e4SDavid E. O'Brien * Most stuff with builtins is incorrect 5c80476e4SDavid E. O'Brien */ 6c80476e4SDavid E. O'Brien /*- 7c80476e4SDavid E. O'Brien * Copyright (c) 1980, 1991 The Regents of the University of California. 8c80476e4SDavid E. O'Brien * All rights reserved. 9c80476e4SDavid E. O'Brien * 10c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 11c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions 12c80476e4SDavid E. O'Brien * are met: 13c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 14c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 15c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 16c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 17c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution. 1829301572SMark Peek * 3. Neither the name of the University nor the names of its contributors 19c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software 20c80476e4SDavid E. O'Brien * without specific prior written permission. 21c80476e4SDavid E. O'Brien * 22c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32c80476e4SDavid E. O'Brien * SUCH DAMAGE. 33c80476e4SDavid E. O'Brien */ 34c80476e4SDavid E. O'Brien #include "sh.h" 35c80476e4SDavid E. O'Brien 36*19d2e3deSDmitry Chagin RCSID("$tcsh: sh.sem.c,v 3.90 2015/10/31 18:54:42 christos Exp $") 37c80476e4SDavid E. O'Brien 38c80476e4SDavid E. O'Brien #include "tc.h" 39c80476e4SDavid E. O'Brien #include "tw.h" 403b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE 41c80476e4SDavid E. O'Brien #include "nt.const.h" 423b6eaa7bSAndrey A. Chernov #endif /*WINNT_NATIVE*/ 43c80476e4SDavid E. O'Brien 44c80476e4SDavid E. O'Brien #ifdef CLOSE_ON_EXEC 45c80476e4SDavid E. O'Brien # ifndef SUNOS4 46c80476e4SDavid E. O'Brien # ifndef CLEX_DUPS 47c80476e4SDavid E. O'Brien # define CLEX_DUPS 48c80476e4SDavid E. O'Brien # endif /* CLEX_DUPS */ 49c80476e4SDavid E. O'Brien # endif /* !SUNOS4 */ 50c80476e4SDavid E. O'Brien #endif /* CLOSE_ON_EXEC */ 51c80476e4SDavid E. O'Brien 52c80476e4SDavid E. O'Brien #if defined(__sparc__) || defined(sparc) 539ccc37e3SMark Peek # if !defined(MACH) && SYSVREL == 0 && !defined(Lynx) && !defined(BSD4_4) && !defined(__linux__) && !defined(__GNU__) && !defined(__GLIBC__) 54c80476e4SDavid E. O'Brien # include <vfork.h> 5523338178SMark Peek # endif /* !MACH && SYSVREL == 0 && !Lynx && !BSD4_4 && !glibc */ 56c80476e4SDavid E. O'Brien #endif /* __sparc__ || sparc */ 57c80476e4SDavid E. O'Brien 58c80476e4SDavid E. O'Brien #ifdef VFORK 5945e5710bSMark Peek static void vffree (int); 60c80476e4SDavid E. O'Brien #endif 6145e5710bSMark Peek static Char *splicepipe (struct command *, Char *); 6245e5710bSMark Peek static void doio (struct command *, int *, int *); 6345e5710bSMark Peek static void chkclob (const char *); 64c80476e4SDavid E. O'Brien 65c80476e4SDavid E. O'Brien /* 66c80476e4SDavid E. O'Brien * C shell 67c80476e4SDavid E. O'Brien */ 68c80476e4SDavid E. O'Brien 69c80476e4SDavid E. O'Brien /* 70c80476e4SDavid E. O'Brien * For SVR4, there are problems with pipelines having the first process as 71c80476e4SDavid E. O'Brien * the group leader. The problem occurs when the first process exits before 72c80476e4SDavid E. O'Brien * the others have a chance to setpgid(). This is because in SVR4 you can't 73c80476e4SDavid E. O'Brien * have a zombie as a group leader. The solution I have used is to reverse 74c80476e4SDavid E. O'Brien * the order in which pipelines are started, making the last process the 75c80476e4SDavid E. O'Brien * group leader. (Note I am not using 'pipeline' in the generic sense -- I 76c80476e4SDavid E. O'Brien * mean processes connected by '|'.) I don't know yet if this causes other 77c80476e4SDavid E. O'Brien * problems. 78c80476e4SDavid E. O'Brien * 79c80476e4SDavid E. O'Brien * All the changes for this are in execute(), and are enclosed in 80c80476e4SDavid E. O'Brien * '#ifdef BACKPIPE' 81c80476e4SDavid E. O'Brien * 82c80476e4SDavid E. O'Brien * David Dawes (dawes@physics.su.oz.au) Oct 1991 83c80476e4SDavid E. O'Brien */ 84c80476e4SDavid E. O'Brien 85c80476e4SDavid E. O'Brien /*VARARGS 1*/ 86c80476e4SDavid E. O'Brien void 8745e5710bSMark Peek execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout, 8845e5710bSMark Peek int do_glob) 89c80476e4SDavid E. O'Brien { 9023338178SMark Peek int forked = 0; 9145e5710bSMark Peek const struct biltins * volatile bifunc; 9245e5710bSMark Peek pid_t pid = 0; 93c80476e4SDavid E. O'Brien int pv[2]; 9445e5710bSMark Peek sigset_t set; 9545e5710bSMark Peek static sigset_t csigset; 96c80476e4SDavid E. O'Brien #ifdef VFORK 97c80476e4SDavid E. O'Brien static int onosigchld = 0; 98c80476e4SDavid E. O'Brien #endif /* VFORK */ 99c80476e4SDavid E. O'Brien static int nosigchld = 0; 100c80476e4SDavid E. O'Brien 101c80476e4SDavid E. O'Brien (void) &wanttty; 102c80476e4SDavid E. O'Brien (void) &forked; 103c80476e4SDavid E. O'Brien (void) &bifunc; 104c80476e4SDavid E. O'Brien 105c80476e4SDavid E. O'Brien if (t == 0) 106c80476e4SDavid E. O'Brien return; 107c80476e4SDavid E. O'Brien 1083b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE 109c80476e4SDavid E. O'Brien { 110c80476e4SDavid E. O'Brien if ((varval(STRNTslowexec) == STRNULL) && 111c80476e4SDavid E. O'Brien !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds && 112c80476e4SDavid E. O'Brien (intty || intact) && (t->t_dtyp == NODE_COMMAND) && 113c80476e4SDavid E. O'Brien !isbfunc(t)) { 114c80476e4SDavid E. O'Brien if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) 115c80476e4SDavid E. O'Brien (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); 116c80476e4SDavid E. O'Brien Dfix(t); 117c80476e4SDavid E. O'Brien if (nt_try_fast_exec(t) == 0) 118c80476e4SDavid E. O'Brien return; 119c80476e4SDavid E. O'Brien } 120c80476e4SDavid E. O'Brien } 1213b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */ 122c80476e4SDavid E. O'Brien 123c80476e4SDavid E. O'Brien /* 124c80476e4SDavid E. O'Brien * Ed hutchins@sgi.com & Dominic dbg@sgi.com 125c80476e4SDavid E. O'Brien * Sat Feb 25 03:13:11 PST 1995 126c80476e4SDavid E. O'Brien * try implicit cd if we have a 1 word command 127c80476e4SDavid E. O'Brien */ 128c80476e4SDavid E. O'Brien if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] && 129c80476e4SDavid E. O'Brien t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) { 13045e5710bSMark Peek Char *sCName; 131c80476e4SDavid E. O'Brien struct stat stbuf; 132c80476e4SDavid E. O'Brien char *pathname; 133c80476e4SDavid E. O'Brien 13445e5710bSMark Peek sCName = dollar(t->t_dcom[0]); 13545e5710bSMark Peek if (sCName != NULL && sCName[0] == '~') { 13645e5710bSMark Peek struct Strbuf buf = Strbuf_INIT; 13745e5710bSMark Peek const Char *name_end; 138c80476e4SDavid E. O'Brien 13945e5710bSMark Peek for (name_end = sCName + 1; *name_end != '\0' && *name_end != '/'; 14045e5710bSMark Peek name_end++) 14145e5710bSMark Peek continue; 14245e5710bSMark Peek if (name_end != sCName + 1) { 14345e5710bSMark Peek Char *name, *home; 14445e5710bSMark Peek 14545e5710bSMark Peek name = Strnsave(sCName + 1, name_end - (sCName + 1)); 14645e5710bSMark Peek home = gethdir(name); 14745e5710bSMark Peek if (home != NULL) { 14845e5710bSMark Peek Strbuf_append(&buf, home); 14945e5710bSMark Peek xfree(home); 15045e5710bSMark Peek } else 15145e5710bSMark Peek Strbuf_append(&buf, name); 15245e5710bSMark Peek xfree(name); 15345e5710bSMark Peek } else 15445e5710bSMark Peek Strbuf_append(&buf, varval(STRhome)); 15545e5710bSMark Peek Strbuf_append(&buf, name_end); 15645e5710bSMark Peek xfree(sCName); 15745e5710bSMark Peek sCName = Strbuf_finish(&buf); 158c80476e4SDavid E. O'Brien } 159c80476e4SDavid E. O'Brien 160c80476e4SDavid E. O'Brien pathname = short2str(sCName); 16145e5710bSMark Peek xfree(sCName); 162c80476e4SDavid E. O'Brien /* if this is a dir, tack a "cd" on as the first arg */ 16345e5710bSMark Peek if (pathname != NULL && 16445e5710bSMark Peek ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode)) 1653b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE 166c80476e4SDavid E. O'Brien || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0') 1673b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */ 16845e5710bSMark Peek )) { 169c80476e4SDavid E. O'Brien Char *vCD[2]; 170c80476e4SDavid E. O'Brien Char **ot_dcom = t->t_dcom; 171c80476e4SDavid E. O'Brien 172c80476e4SDavid E. O'Brien vCD[0] = Strsave(STRcd); 173c80476e4SDavid E. O'Brien vCD[1] = NULL; 174c80476e4SDavid E. O'Brien t->t_dcom = blkspl(vCD, ot_dcom); 17545e5710bSMark Peek xfree(ot_dcom); 176c80476e4SDavid E. O'Brien if (implicit_cd > 1) { 177c80476e4SDavid E. O'Brien blkpr(t->t_dcom); 178c80476e4SDavid E. O'Brien xputchar( '\n' ); 179c80476e4SDavid E. O'Brien } 180c80476e4SDavid E. O'Brien } 181c80476e4SDavid E. O'Brien } 182c80476e4SDavid E. O'Brien 183c80476e4SDavid E. O'Brien /* 184c80476e4SDavid E. O'Brien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 185c80476e4SDavid E. O'Brien * Don't check for wantty > 0... 186c80476e4SDavid E. O'Brien */ 187c80476e4SDavid E. O'Brien if (t->t_dflg & F_AMPERSAND) 188c80476e4SDavid E. O'Brien wanttty = 0; 189c80476e4SDavid E. O'Brien switch (t->t_dtyp) { 190c80476e4SDavid E. O'Brien 191c80476e4SDavid E. O'Brien case NODE_COMMAND: 192c80476e4SDavid E. O'Brien if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) 19345e5710bSMark Peek memmove(t->t_dcom[0], t->t_dcom[0] + 1, 19445e5710bSMark Peek (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0])); 195c80476e4SDavid E. O'Brien if ((t->t_dflg & F_REPEAT) == 0) 196c80476e4SDavid E. O'Brien Dfix(t); /* $ " ' \ */ 197c80476e4SDavid E. O'Brien if (t->t_dcom[0] == 0) { 198c80476e4SDavid E. O'Brien return; 199c80476e4SDavid E. O'Brien } 200c80476e4SDavid E. O'Brien /*FALLTHROUGH*/ 201c80476e4SDavid E. O'Brien 202c80476e4SDavid E. O'Brien case NODE_PAREN: 203c80476e4SDavid E. O'Brien #ifdef BACKPIPE 204c80476e4SDavid E. O'Brien if (t->t_dflg & F_PIPEIN) 205c80476e4SDavid E. O'Brien mypipe(pipein); 206c80476e4SDavid E. O'Brien #else /* !BACKPIPE */ 207c80476e4SDavid E. O'Brien if (t->t_dflg & F_PIPEOUT) 208c80476e4SDavid E. O'Brien mypipe(pipeout); 209c80476e4SDavid E. O'Brien #endif /* BACKPIPE */ 210c80476e4SDavid E. O'Brien /* 211c80476e4SDavid E. O'Brien * Must do << early so parent will know where input pointer should be. 212c80476e4SDavid E. O'Brien * If noexec then this is all we do. 213c80476e4SDavid E. O'Brien */ 214c80476e4SDavid E. O'Brien if (t->t_dflg & F_READ) { 215*19d2e3deSDmitry Chagin int old_pintr_disabled; 216*19d2e3deSDmitry Chagin 21745e5710bSMark Peek xclose(0); 218*19d2e3deSDmitry Chagin if (setintr) 219*19d2e3deSDmitry Chagin pintr_push_enable(&old_pintr_disabled); 220c80476e4SDavid E. O'Brien heredoc(t->t_dlef); 221*19d2e3deSDmitry Chagin if (setintr) 222*19d2e3deSDmitry Chagin cleanup_until(&old_pintr_disabled); 223c80476e4SDavid E. O'Brien if (noexec) 22445e5710bSMark Peek xclose(0); 225c80476e4SDavid E. O'Brien } 226c80476e4SDavid E. O'Brien 22745e5710bSMark Peek setcopy(STRstatus, STR0, VAR_READWRITE); 228c80476e4SDavid E. O'Brien 229c80476e4SDavid E. O'Brien /* 230c80476e4SDavid E. O'Brien * This mess is the necessary kludge to handle the prefix builtins: 231c80476e4SDavid E. O'Brien * nice, nohup, time. These commands can also be used by themselves, 232c80476e4SDavid E. O'Brien * and this is not handled here. This will also work when loops are 233c80476e4SDavid E. O'Brien * parsed. 234c80476e4SDavid E. O'Brien */ 235c80476e4SDavid E. O'Brien while (t->t_dtyp == NODE_COMMAND) 236c80476e4SDavid E. O'Brien if (eq(t->t_dcom[0], STRnice)) { 237c80476e4SDavid E. O'Brien if (t->t_dcom[1]) { 238c80476e4SDavid E. O'Brien if (strchr("+-", t->t_dcom[1][0])) { 239c80476e4SDavid E. O'Brien if (t->t_dcom[2]) { 240c80476e4SDavid E. O'Brien setname("nice"); 2419ccc37e3SMark Peek t->t_nice = (unsigned char)getn(t->t_dcom[1]); 242c80476e4SDavid E. O'Brien lshift(t->t_dcom, 2); 243c80476e4SDavid E. O'Brien t->t_dflg |= F_NICE; 244c80476e4SDavid E. O'Brien } 245c80476e4SDavid E. O'Brien else 246c80476e4SDavid E. O'Brien break; 247c80476e4SDavid E. O'Brien } 248c80476e4SDavid E. O'Brien else { 249c80476e4SDavid E. O'Brien t->t_nice = 4; 250c80476e4SDavid E. O'Brien lshift(t->t_dcom, 1); 251c80476e4SDavid E. O'Brien t->t_dflg |= F_NICE; 252c80476e4SDavid E. O'Brien } 253c80476e4SDavid E. O'Brien } 254c80476e4SDavid E. O'Brien else 255c80476e4SDavid E. O'Brien break; 256c80476e4SDavid E. O'Brien } 257c80476e4SDavid E. O'Brien else if (eq(t->t_dcom[0], STRnohup)) { 258c80476e4SDavid E. O'Brien if (t->t_dcom[1]) { 259c80476e4SDavid E. O'Brien t->t_dflg |= F_NOHUP; 260c80476e4SDavid E. O'Brien lshift(t->t_dcom, 1); 261c80476e4SDavid E. O'Brien } 262c80476e4SDavid E. O'Brien else 263c80476e4SDavid E. O'Brien break; 264c80476e4SDavid E. O'Brien } 265c80476e4SDavid E. O'Brien else if (eq(t->t_dcom[0], STRhup)) { 266c80476e4SDavid E. O'Brien if (t->t_dcom[1]) { 267c80476e4SDavid E. O'Brien t->t_dflg |= F_HUP; 268c80476e4SDavid E. O'Brien lshift(t->t_dcom, 1); 269c80476e4SDavid E. O'Brien } 270c80476e4SDavid E. O'Brien else 271c80476e4SDavid E. O'Brien break; 272c80476e4SDavid E. O'Brien } 273c80476e4SDavid E. O'Brien else if (eq(t->t_dcom[0], STRtime)) { 274c80476e4SDavid E. O'Brien if (t->t_dcom[1]) { 275c80476e4SDavid E. O'Brien t->t_dflg |= F_TIME; 276c80476e4SDavid E. O'Brien lshift(t->t_dcom, 1); 277c80476e4SDavid E. O'Brien } 278c80476e4SDavid E. O'Brien else 279c80476e4SDavid E. O'Brien break; 280c80476e4SDavid E. O'Brien } 281c80476e4SDavid E. O'Brien #ifdef F_VER 282c80476e4SDavid E. O'Brien else if (eq(t->t_dcom[0], STRver)) 283c80476e4SDavid E. O'Brien if (t->t_dcom[1] && t->t_dcom[2]) { 284c80476e4SDavid E. O'Brien setname("ver"); 285c80476e4SDavid E. O'Brien t->t_systype = getv(t->t_dcom[1]); 286c80476e4SDavid E. O'Brien lshift(t->t_dcom, 2); 287c80476e4SDavid E. O'Brien t->t_dflg |= F_VER; 288c80476e4SDavid E. O'Brien } 289c80476e4SDavid E. O'Brien else 290c80476e4SDavid E. O'Brien break; 291c80476e4SDavid E. O'Brien #endif /* F_VER */ 292c80476e4SDavid E. O'Brien else 293c80476e4SDavid E. O'Brien break; 294c80476e4SDavid E. O'Brien 295c80476e4SDavid E. O'Brien /* is it a command */ 296c80476e4SDavid E. O'Brien if (t->t_dtyp == NODE_COMMAND) { 297c80476e4SDavid E. O'Brien /* 298c80476e4SDavid E. O'Brien * Check if we have a builtin function and remember which one. 299c80476e4SDavid E. O'Brien */ 300c80476e4SDavid E. O'Brien bifunc = isbfunc(t); 30145e5710bSMark Peek if (noexec) { 302c80476e4SDavid E. O'Brien /* 303c80476e4SDavid E. O'Brien * Continue for builtins that are part of the scripting language 304c80476e4SDavid E. O'Brien */ 30545e5710bSMark Peek if (bifunc == NULL) 30645e5710bSMark Peek break; 307c80476e4SDavid E. O'Brien if (bifunc->bfunct != (bfunc_t)dobreak && 308c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)docontin && 309c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)doelse && 310c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)doend && 311c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)doforeach&& 312c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)dogoto && 313c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)doif && 314c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)dorepeat && 315c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)doswbrk && 316c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)doswitch && 317c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)dowhile && 318c80476e4SDavid E. O'Brien bifunc->bfunct != (bfunc_t)dozip) 319c80476e4SDavid E. O'Brien break; 320c80476e4SDavid E. O'Brien } 321c80476e4SDavid E. O'Brien } 322c80476e4SDavid E. O'Brien else { /* not a command */ 323c80476e4SDavid E. O'Brien bifunc = NULL; 324c80476e4SDavid E. O'Brien if (noexec) 325c80476e4SDavid E. O'Brien break; 326c80476e4SDavid E. O'Brien } 327c80476e4SDavid E. O'Brien 328c80476e4SDavid E. O'Brien /* 3296767bd61SMark Peek * GrP Executing a command - run jobcmd hook 3306767bd61SMark Peek * Don't run for builtins 3316767bd61SMark Peek * Don't run if we're not in a tty 3326767bd61SMark Peek * Don't run if we're not really executing 3336767bd61SMark Peek */ 334a15e6f9aSMark Peek /* 335a15e6f9aSMark Peek * CR - Charles Ross Aug 2005 336a15e6f9aSMark Peek * added "isoutatty". 337a15e6f9aSMark Peek * The new behavior is that the jobcmd won't be executed 338a15e6f9aSMark Peek * if stdout (SHOUT) isnt attached to a tty.. IE when 339a15e6f9aSMark Peek * redirecting, or using backquotes etc.. 340a15e6f9aSMark Peek */ 341a15e6f9aSMark Peek if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty && isoutatty) { 3426767bd61SMark Peek Char *cmd = unparse(t); 34345e5710bSMark Peek 34445e5710bSMark Peek cleanup_push(cmd, xfree); 3456767bd61SMark Peek job_cmd(cmd); 34645e5710bSMark Peek cleanup_until(cmd); 3476767bd61SMark Peek } 3486767bd61SMark Peek 3496767bd61SMark Peek /* 350c80476e4SDavid E. O'Brien * We fork only if we are timed, or are not the end of a parenthesized 351c80476e4SDavid E. O'Brien * list and not a simple builtin function. Simple meaning one that is 352c80476e4SDavid E. O'Brien * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not 353c80476e4SDavid E. O'Brien * fork in some of these cases. 354c80476e4SDavid E. O'Brien */ 355c80476e4SDavid E. O'Brien #ifdef BACKPIPE 356c80476e4SDavid E. O'Brien /* 357c80476e4SDavid E. O'Brien * Can't have NOFORK for the tail of a pipe - because it is not the 358c80476e4SDavid E. O'Brien * last command spawned (even if it is at the end of a parenthesised 359c80476e4SDavid E. O'Brien * list). 360c80476e4SDavid E. O'Brien */ 361c80476e4SDavid E. O'Brien if (t->t_dflg & F_PIPEIN) 362c80476e4SDavid E. O'Brien t->t_dflg &= ~(F_NOFORK); 363*19d2e3deSDmitry Chagin #else 364*19d2e3deSDmitry Chagin /* 365*19d2e3deSDmitry Chagin * "command | builtin" may cause major misbehaviour as noted in 366*19d2e3deSDmitry Chagin * in the BUGS file entry 367*19d2e3deSDmitry Chagin * Subject: Redirected input to built-in functions misbehaves badly 368*19d2e3deSDmitry Chagin * forking when the builtin is the end of the pipe corrects the 369*19d2e3deSDmitry Chagin * problem. 370*19d2e3deSDmitry Chagin */ 371*19d2e3deSDmitry Chagin if (bifunc && (t->t_dflg & F_PIPEIN)) 372*19d2e3deSDmitry Chagin t->t_dflg &= ~(F_NOFORK); 373c80476e4SDavid E. O'Brien #endif /* BACKPIPE */ 374*19d2e3deSDmitry Chagin /* 375*19d2e3deSDmitry Chagin * Prevent forking cd, pushd, popd, chdir cause this will cause the 376*19d2e3deSDmitry Chagin * shell not to change dir! (XXX: but only for nice?) 377*19d2e3deSDmitry Chagin */ 378c80476e4SDavid E. O'Brien if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd || 379c80476e4SDavid E. O'Brien bifunc->bfunct == (bfunc_t)dopushd || 380c80476e4SDavid E. O'Brien bifunc->bfunct == (bfunc_t)dopopd)) 381c80476e4SDavid E. O'Brien t->t_dflg &= ~(F_NICE); 382*19d2e3deSDmitry Chagin 383c80476e4SDavid E. O'Brien if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && 384c80476e4SDavid E. O'Brien (!bifunc || t->t_dflg & 385c80476e4SDavid E. O'Brien (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) || 386c80476e4SDavid E. O'Brien /* 387c80476e4SDavid E. O'Brien * We have to fork for eval too. 388c80476e4SDavid E. O'Brien */ 389c80476e4SDavid E. O'Brien (bifunc && (t->t_dflg & F_PIPEIN) != 0 && 3903b6eaa7bSAndrey A. Chernov bifunc->bfunct == (bfunc_t)doeval)) { 391c80476e4SDavid E. O'Brien #ifdef VFORK 392c80476e4SDavid E. O'Brien if (t->t_dtyp == NODE_PAREN || 393c80476e4SDavid E. O'Brien t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) 394c80476e4SDavid E. O'Brien #endif /* VFORK */ 395c80476e4SDavid E. O'Brien { 396c80476e4SDavid E. O'Brien forked++; 397c80476e4SDavid E. O'Brien /* 398c80476e4SDavid E. O'Brien * We need to block SIGCHLD here, so that if the process does 399c80476e4SDavid E. O'Brien * not die before we can set the process group 400c80476e4SDavid E. O'Brien */ 401c80476e4SDavid E. O'Brien if (wanttty >= 0 && !nosigchld) { 40245e5710bSMark Peek sigemptyset(&set); 40345e5710bSMark Peek sigaddset(&set, SIGCHLD); 40445e5710bSMark Peek (void)sigprocmask(SIG_BLOCK, &set, &csigset); 405c80476e4SDavid E. O'Brien 406c80476e4SDavid E. O'Brien nosigchld = 1; 407c80476e4SDavid E. O'Brien } 408c80476e4SDavid E. O'Brien 409c80476e4SDavid E. O'Brien pid = pfork(t, wanttty); 410c80476e4SDavid E. O'Brien if (pid == 0 && nosigchld) { 41145e5710bSMark Peek sigprocmask(SIG_SETMASK, &csigset, NULL); 412c80476e4SDavid E. O'Brien nosigchld = 0; 413c80476e4SDavid E. O'Brien } 414c80476e4SDavid E. O'Brien else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) 415c80476e4SDavid E. O'Brien backpid = pid; 416c80476e4SDavid E. O'Brien } 417c80476e4SDavid E. O'Brien 418c80476e4SDavid E. O'Brien #ifdef VFORK 419c80476e4SDavid E. O'Brien else { 420c80476e4SDavid E. O'Brien int ochild, osetintr, ohaderr, odidfds; 421c80476e4SDavid E. O'Brien int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; 422c80476e4SDavid E. O'Brien int oisoutatty, oisdiagatty; 42345e5710bSMark Peek sigset_t oset, ocsigset; 424c80476e4SDavid E. O'Brien # ifndef CLOSE_ON_EXEC 425c80476e4SDavid E. O'Brien int odidcch; 426c80476e4SDavid E. O'Brien # endif /* !CLOSE_ON_EXEC */ 427c80476e4SDavid E. O'Brien 428c80476e4SDavid E. O'Brien /* 429c80476e4SDavid E. O'Brien * Prepare for the vfork by saving everything that the child 430c80476e4SDavid E. O'Brien * corrupts before it exec's. Note that in some signal 431c80476e4SDavid E. O'Brien * implementations which keep the signal info in user space 432c80476e4SDavid E. O'Brien * (e.g. Sun's) it will also be necessary to save and restore 433c80476e4SDavid E. O'Brien * the current sigvec's for the signals the child touches 434c80476e4SDavid E. O'Brien * before it exec's. 435c80476e4SDavid E. O'Brien */ 436c80476e4SDavid E. O'Brien 437c80476e4SDavid E. O'Brien /* 438c80476e4SDavid E. O'Brien * Sooooo true... If this is a Sun, save the sigvec's. (Skip 439c80476e4SDavid E. O'Brien * Gilbrech - 11/22/87) 440c80476e4SDavid E. O'Brien */ 441c80476e4SDavid E. O'Brien # ifdef SAVESIGVEC 44245e5710bSMark Peek struct sigaction savesv[NSIGSAVED]; 44345e5710bSMark Peek sigset_t savesm; 444c80476e4SDavid E. O'Brien 445c80476e4SDavid E. O'Brien # endif /* SAVESIGVEC */ 446c80476e4SDavid E. O'Brien if (wanttty >= 0 && !nosigchld && !noexec) { 44745e5710bSMark Peek sigemptyset(&set); 44845e5710bSMark Peek sigaddset(&set, SIGCHLD); 44945e5710bSMark Peek (void)sigprocmask(SIG_BLOCK, &set, &csigset); 450c80476e4SDavid E. O'Brien nosigchld = 1; 451c80476e4SDavid E. O'Brien } 45245e5710bSMark Peek sigemptyset(&set); 45345e5710bSMark Peek sigaddset(&set, SIGCHLD); 45445e5710bSMark Peek sigaddset(&set, SIGINT); 45545e5710bSMark Peek (void)sigprocmask(SIG_BLOCK, &set, &oset); 456c80476e4SDavid E. O'Brien ochild = child; 457c80476e4SDavid E. O'Brien osetintr = setintr; 458c80476e4SDavid E. O'Brien ohaderr = haderr; 459c80476e4SDavid E. O'Brien odidfds = didfds; 460c80476e4SDavid E. O'Brien # ifndef CLOSE_ON_EXEC 461c80476e4SDavid E. O'Brien odidcch = didcch; 462c80476e4SDavid E. O'Brien # endif /* !CLOSE_ON_EXEC */ 463c80476e4SDavid E. O'Brien oSHIN = SHIN; 464c80476e4SDavid E. O'Brien oSHOUT = SHOUT; 465c80476e4SDavid E. O'Brien oSHDIAG = SHDIAG; 466c80476e4SDavid E. O'Brien oOLDSTD = OLDSTD; 467c80476e4SDavid E. O'Brien otpgrp = tpgrp; 468c80476e4SDavid E. O'Brien oisoutatty = isoutatty; 469c80476e4SDavid E. O'Brien oisdiagatty = isdiagatty; 47045e5710bSMark Peek ocsigset = csigset; 471c80476e4SDavid E. O'Brien onosigchld = nosigchld; 472c80476e4SDavid E. O'Brien Vsav = Vdp = 0; 473c80476e4SDavid E. O'Brien Vexpath = 0; 474c80476e4SDavid E. O'Brien Vt = 0; 475c80476e4SDavid E. O'Brien # ifdef SAVESIGVEC 47645e5710bSMark Peek savesigvec(savesv, savesm); 477c80476e4SDavid E. O'Brien # endif /* SAVESIGVEC */ 478c80476e4SDavid E. O'Brien if (use_fork) 479c80476e4SDavid E. O'Brien pid = fork(); 480c80476e4SDavid E. O'Brien else 481c80476e4SDavid E. O'Brien pid = vfork(); 482c80476e4SDavid E. O'Brien 483c80476e4SDavid E. O'Brien if (pid < 0) { 484c80476e4SDavid E. O'Brien # ifdef SAVESIGVEC 485c80476e4SDavid E. O'Brien restoresigvec(savesv, savesm); 486c80476e4SDavid E. O'Brien # endif /* SAVESIGVEC */ 48745e5710bSMark Peek sigprocmask(SIG_SETMASK, &oset, NULL); 488c80476e4SDavid E. O'Brien stderror(ERR_NOPROC); 489c80476e4SDavid E. O'Brien } 490c80476e4SDavid E. O'Brien forked++; 491c80476e4SDavid E. O'Brien if (pid) { /* parent */ 492c80476e4SDavid E. O'Brien # ifdef SAVESIGVEC 493c80476e4SDavid E. O'Brien restoresigvec(savesv, savesm); 494c80476e4SDavid E. O'Brien # endif /* SAVESIGVEC */ 495c80476e4SDavid E. O'Brien child = ochild; 496c80476e4SDavid E. O'Brien setintr = osetintr; 497c80476e4SDavid E. O'Brien haderr = ohaderr; 498c80476e4SDavid E. O'Brien didfds = odidfds; 499c80476e4SDavid E. O'Brien SHIN = oSHIN; 500c80476e4SDavid E. O'Brien # ifndef CLOSE_ON_EXEC 501c80476e4SDavid E. O'Brien didcch = odidcch; 502c80476e4SDavid E. O'Brien # endif /* !CLOSE_ON_EXEC */ 503c80476e4SDavid E. O'Brien SHOUT = oSHOUT; 504c80476e4SDavid E. O'Brien SHDIAG = oSHDIAG; 505c80476e4SDavid E. O'Brien OLDSTD = oOLDSTD; 506c80476e4SDavid E. O'Brien tpgrp = otpgrp; 507c80476e4SDavid E. O'Brien isoutatty = oisoutatty; 508c80476e4SDavid E. O'Brien isdiagatty = oisdiagatty; 50945e5710bSMark Peek csigset = ocsigset; 510c80476e4SDavid E. O'Brien nosigchld = onosigchld; 511c80476e4SDavid E. O'Brien 51245e5710bSMark Peek xfree(Vsav); 513c80476e4SDavid E. O'Brien Vsav = 0; 51445e5710bSMark Peek xfree(Vdp); 515c80476e4SDavid E. O'Brien Vdp = 0; 51645e5710bSMark Peek xfree(Vexpath); 517c80476e4SDavid E. O'Brien Vexpath = 0; 51845e5710bSMark Peek blk_cleanup(Vt); 519c80476e4SDavid E. O'Brien Vt = 0; 520c80476e4SDavid E. O'Brien /* this is from pfork() */ 521c80476e4SDavid E. O'Brien palloc(pid, t); 52245e5710bSMark Peek sigprocmask(SIG_SETMASK, &oset, NULL); 523c80476e4SDavid E. O'Brien } 524c80476e4SDavid E. O'Brien else { /* child */ 525c80476e4SDavid E. O'Brien /* this is from pfork() */ 52645e5710bSMark Peek pid_t pgrp; 52723338178SMark Peek int ignint = 0; 528c80476e4SDavid E. O'Brien if (nosigchld) { 52945e5710bSMark Peek sigprocmask(SIG_SETMASK, &csigset, NULL); 530c80476e4SDavid E. O'Brien nosigchld = 0; 531c80476e4SDavid E. O'Brien } 532c80476e4SDavid E. O'Brien 533c80476e4SDavid E. O'Brien if (setintr) 534c80476e4SDavid E. O'Brien ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 535c80476e4SDavid E. O'Brien || (gointr && eq(gointr, STRminus)); 536c80476e4SDavid E. O'Brien pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 537c80476e4SDavid E. O'Brien child++; 538c80476e4SDavid E. O'Brien if (setintr) { 539c80476e4SDavid E. O'Brien setintr = 0; 540c80476e4SDavid E. O'Brien /* 541c80476e4SDavid E. O'Brien * casts made right for SunOS 4.0 by Douglas C. Schmidt 542c80476e4SDavid E. O'Brien * <schmidt%sunshine.ics.uci.edu@ROME.ICS.UCI.EDU> 543c80476e4SDavid E. O'Brien * (thanks! -- PWP) 544c80476e4SDavid E. O'Brien * 545c80476e4SDavid E. O'Brien * ignint ifs cleaned by Johan Widen <mcvax!osiris.sics.se!jw@uunet.UU.NET> 546c80476e4SDavid E. O'Brien * (thanks again) 547c80476e4SDavid E. O'Brien */ 548c80476e4SDavid E. O'Brien if (ignint) { 549c80476e4SDavid E. O'Brien (void) signal(SIGINT, SIG_IGN); 550c80476e4SDavid E. O'Brien (void) signal(SIGQUIT, SIG_IGN); 551c80476e4SDavid E. O'Brien } 552c80476e4SDavid E. O'Brien else { 553c80476e4SDavid E. O'Brien (void) signal(SIGINT, vffree); 554c80476e4SDavid E. O'Brien (void) signal(SIGQUIT, SIG_DFL); 555c80476e4SDavid E. O'Brien } 556c80476e4SDavid E. O'Brien # ifdef BSDJOBS 557c80476e4SDavid E. O'Brien if (wanttty >= 0) { 558c80476e4SDavid E. O'Brien (void) signal(SIGTSTP, SIG_DFL); 559c80476e4SDavid E. O'Brien (void) signal(SIGTTIN, SIG_DFL); 560c80476e4SDavid E. O'Brien (void) signal(SIGTTOU, SIG_DFL); 561c80476e4SDavid E. O'Brien } 562c80476e4SDavid E. O'Brien # endif /* BSDJOBS */ 563c80476e4SDavid E. O'Brien 56445e5710bSMark Peek sigaction(SIGTERM, &parterm, NULL); 565c80476e4SDavid E. O'Brien } 566c80476e4SDavid E. O'Brien else if (tpgrp == -1 && 567c80476e4SDavid E. O'Brien (t->t_dflg & F_NOINTERRUPT)) { 568c80476e4SDavid E. O'Brien (void) signal(SIGINT, SIG_IGN); 569c80476e4SDavid E. O'Brien (void) signal(SIGQUIT, SIG_IGN); 570c80476e4SDavid E. O'Brien } 571c80476e4SDavid E. O'Brien 572c80476e4SDavid E. O'Brien pgetty(wanttty, pgrp); 573c80476e4SDavid E. O'Brien 574c80476e4SDavid E. O'Brien if (t->t_dflg & F_NOHUP) 575c80476e4SDavid E. O'Brien (void) signal(SIGHUP, SIG_IGN); 576c80476e4SDavid E. O'Brien if (t->t_dflg & F_HUP) 577c80476e4SDavid E. O'Brien (void) signal(SIGHUP, SIG_DFL); 578c80476e4SDavid E. O'Brien if (t->t_dflg & F_NICE) { 579c80476e4SDavid E. O'Brien int nval = SIGN_EXTEND_CHAR(t->t_nice); 580*19d2e3deSDmitry Chagin # if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) 5816767bd61SMark Peek if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) 5826767bd61SMark Peek stderror(ERR_SYSTEM, "setpriority", 5836767bd61SMark Peek strerror(errno)); 584*19d2e3deSDmitry Chagin # else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */ 585c80476e4SDavid E. O'Brien (void) nice(nval); 586*19d2e3deSDmitry Chagin # endif /* HAVE_SETPRIORITY && PRIO_PROCESS */ 587c80476e4SDavid E. O'Brien } 588c80476e4SDavid E. O'Brien # ifdef F_VER 589c80476e4SDavid E. O'Brien if (t->t_dflg & F_VER) { 590c80476e4SDavid E. O'Brien tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 591c80476e4SDavid E. O'Brien dohash(NULL, NULL); 592c80476e4SDavid E. O'Brien } 593c80476e4SDavid E. O'Brien # endif /* F_VER */ 594c80476e4SDavid E. O'Brien } 595c80476e4SDavid E. O'Brien 596c80476e4SDavid E. O'Brien } 597c80476e4SDavid E. O'Brien #endif /* VFORK */ 5983b6eaa7bSAndrey A. Chernov } 599c80476e4SDavid E. O'Brien if (pid != 0) { 600c80476e4SDavid E. O'Brien /* 601c80476e4SDavid E. O'Brien * It would be better if we could wait for the whole job when we 602c80476e4SDavid E. O'Brien * knew the last process had been started. Pwait, in fact, does 603c80476e4SDavid E. O'Brien * wait for the whole job anyway, but this test doesn't really 604c80476e4SDavid E. O'Brien * express our intentions. 605c80476e4SDavid E. O'Brien */ 606c80476e4SDavid E. O'Brien #ifdef BACKPIPE 607c80476e4SDavid E. O'Brien if (didfds == 0 && t->t_dflg & F_PIPEOUT) { 60845e5710bSMark Peek xclose(pipeout[0]); 60945e5710bSMark Peek xclose(pipeout[1]); 610c80476e4SDavid E. O'Brien } 611c80476e4SDavid E. O'Brien if ((t->t_dflg & F_PIPEIN) != 0) 612c80476e4SDavid E. O'Brien break; 613c80476e4SDavid E. O'Brien #else /* !BACKPIPE */ 614c80476e4SDavid E. O'Brien if (didfds == 0 && t->t_dflg & F_PIPEIN) { 61545e5710bSMark Peek xclose(pipein[0]); 61645e5710bSMark Peek xclose(pipein[1]); 617c80476e4SDavid E. O'Brien } 618c80476e4SDavid E. O'Brien if ((t->t_dflg & F_PIPEOUT) != 0) 619c80476e4SDavid E. O'Brien break; 620c80476e4SDavid E. O'Brien #endif /* BACKPIPE */ 621c80476e4SDavid E. O'Brien 622c80476e4SDavid E. O'Brien if (nosigchld) { 62345e5710bSMark Peek sigprocmask(SIG_SETMASK, &csigset, NULL); 624c80476e4SDavid E. O'Brien nosigchld = 0; 625c80476e4SDavid E. O'Brien } 626c80476e4SDavid E. O'Brien if ((t->t_dflg & F_AMPERSAND) == 0) 627c80476e4SDavid E. O'Brien pwait(); 628c80476e4SDavid E. O'Brien break; 629c80476e4SDavid E. O'Brien } 630c80476e4SDavid E. O'Brien 631c80476e4SDavid E. O'Brien doio(t, pipein, pipeout); 632c80476e4SDavid E. O'Brien #ifdef BACKPIPE 633c80476e4SDavid E. O'Brien if (t->t_dflg & F_PIPEIN) { 63445e5710bSMark Peek xclose(pipein[0]); 63545e5710bSMark Peek xclose(pipein[1]); 636c80476e4SDavid E. O'Brien } 637c80476e4SDavid E. O'Brien #else /* !BACKPIPE */ 638c80476e4SDavid E. O'Brien if (t->t_dflg & F_PIPEOUT) { 63945e5710bSMark Peek xclose(pipeout[0]); 64045e5710bSMark Peek xclose(pipeout[1]); 641c80476e4SDavid E. O'Brien } 642c80476e4SDavid E. O'Brien #endif /* BACKPIPE */ 643c80476e4SDavid E. O'Brien /* 644c80476e4SDavid E. O'Brien * Perform a builtin function. If we are not forked, arrange for 645c80476e4SDavid E. O'Brien * possible stopping 646c80476e4SDavid E. O'Brien */ 647c80476e4SDavid E. O'Brien if (bifunc) { 6489ccc37e3SMark Peek if (forked) { 649c80476e4SDavid E. O'Brien func(t, bifunc); 650c80476e4SDavid E. O'Brien exitstat(); 6519ccc37e3SMark Peek } else { 6529ccc37e3SMark Peek jmp_buf_t oldexit; 6539ccc37e3SMark Peek int ohaderr = haderr; 6549ccc37e3SMark Peek 6559ccc37e3SMark Peek getexit(oldexit); 6569ccc37e3SMark Peek if (setexit() == 0) 6579ccc37e3SMark Peek func(t, bifunc); 6589ccc37e3SMark Peek resexit(oldexit); 6599ccc37e3SMark Peek haderr = ohaderr; 6609ccc37e3SMark Peek 66123338178SMark Peek if (adrof(STRprintexitvalue)) { 66223338178SMark Peek int rv = getn(varval(STRstatus)); 66323338178SMark Peek if (rv != 0) 66423338178SMark Peek xprintf(CGETS(17, 2, "Exit %d\n"), rv); 66523338178SMark Peek } 66623338178SMark Peek } 667c80476e4SDavid E. O'Brien break; 668c80476e4SDavid E. O'Brien } 669c80476e4SDavid E. O'Brien if (t->t_dtyp != NODE_PAREN) { 67029301572SMark Peek doexec(t, do_glob); 671c80476e4SDavid E. O'Brien /* NOTREACHED */ 672c80476e4SDavid E. O'Brien } 673c80476e4SDavid E. O'Brien /* 674c80476e4SDavid E. O'Brien * For () commands must put new 0,1,2 in FSH* and recurse 675c80476e4SDavid E. O'Brien */ 6769ccc37e3SMark Peek if ((OLDSTD = dcopy(0, FOLDSTD)) >= 0) 6779ccc37e3SMark Peek (void)close_on_exec(OLDSTD, 1); 6789ccc37e3SMark Peek if ((SHOUT = dcopy(1, FSHOUT)) >= 0) { 6799ccc37e3SMark Peek (void)close_on_exec(SHOUT, 1); 680c80476e4SDavid E. O'Brien isoutatty = isatty(SHOUT); 6819ccc37e3SMark Peek } 6829ccc37e3SMark Peek if ((SHDIAG = dcopy(2, FSHDIAG)) >= 0) { 6839ccc37e3SMark Peek (void)close_on_exec(SHDIAG, 1); 684c80476e4SDavid E. O'Brien isdiagatty = isatty(SHDIAG); 6859ccc37e3SMark Peek } 68645e5710bSMark Peek xclose(SHIN); 687c80476e4SDavid E. O'Brien SHIN = -1; 688c80476e4SDavid E. O'Brien #ifndef CLOSE_ON_EXEC 689c80476e4SDavid E. O'Brien didcch = 0; 69023338178SMark Peek #else 69123338178SMark Peek (void) close_on_exec(FSHOUT, 1); 69223338178SMark Peek (void) close_on_exec(FSHDIAG, 1); 69323338178SMark Peek (void) close_on_exec(FOLDSTD, 1); 694c80476e4SDavid E. O'Brien #endif /* !CLOSE_ON_EXEC */ 695c80476e4SDavid E. O'Brien didfds = 0; 696c80476e4SDavid E. O'Brien wanttty = -1; 6979ccc37e3SMark Peek t->t_dspr->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); 69829301572SMark Peek execute(t->t_dspr, wanttty, NULL, NULL, do_glob); 699c80476e4SDavid E. O'Brien exitstat(); 700c80476e4SDavid E. O'Brien 701c80476e4SDavid E. O'Brien case NODE_PIPE: 702c80476e4SDavid E. O'Brien #ifdef BACKPIPE 703c80476e4SDavid E. O'Brien t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & 7049ccc37e3SMark Peek (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); 70529301572SMark Peek execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); 7069ccc37e3SMark Peek t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & 7079ccc37e3SMark Peek (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); 70829301572SMark Peek execute(t->t_dcar, wanttty, pipein, pv, do_glob); 709c80476e4SDavid E. O'Brien #else /* !BACKPIPE */ 7109ccc37e3SMark Peek t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & 7119ccc37e3SMark Peek (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); 71229301572SMark Peek execute(t->t_dcar, wanttty, pipein, pv, do_glob); 713c80476e4SDavid E. O'Brien t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & 7149ccc37e3SMark Peek (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); 71529301572SMark Peek execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); 716c80476e4SDavid E. O'Brien #endif /* BACKPIPE */ 717c80476e4SDavid E. O'Brien break; 718c80476e4SDavid E. O'Brien 719c80476e4SDavid E. O'Brien case NODE_LIST: 720c80476e4SDavid E. O'Brien if (t->t_dcar) { 7219ccc37e3SMark Peek t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); 72229301572SMark Peek execute(t->t_dcar, wanttty, NULL, NULL, do_glob); 723c80476e4SDavid E. O'Brien /* 724c80476e4SDavid E. O'Brien * In strange case of A&B make a new job after A 725c80476e4SDavid E. O'Brien */ 726c80476e4SDavid E. O'Brien if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && 727c80476e4SDavid E. O'Brien (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) 728c80476e4SDavid E. O'Brien pendjob(); 729c80476e4SDavid E. O'Brien } 730c80476e4SDavid E. O'Brien if (t->t_dcdr) { 731c80476e4SDavid E. O'Brien t->t_dcdr->t_dflg |= t->t_dflg & 7329ccc37e3SMark Peek (F_NOFORK | F_NOINTERRUPT | F_BACKQ); 73329301572SMark Peek execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); 734c80476e4SDavid E. O'Brien } 735c80476e4SDavid E. O'Brien break; 736c80476e4SDavid E. O'Brien 737c80476e4SDavid E. O'Brien case NODE_OR: 738c80476e4SDavid E. O'Brien case NODE_AND: 739c80476e4SDavid E. O'Brien if (t->t_dcar) { 7409ccc37e3SMark Peek t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); 74129301572SMark Peek execute(t->t_dcar, wanttty, NULL, NULL, do_glob); 742c80476e4SDavid E. O'Brien if ((getn(varval(STRstatus)) == 0) != 743c80476e4SDavid E. O'Brien (t->t_dtyp == NODE_AND)) { 744c80476e4SDavid E. O'Brien return; 745c80476e4SDavid E. O'Brien } 746c80476e4SDavid E. O'Brien } 747c80476e4SDavid E. O'Brien if (t->t_dcdr) { 748c80476e4SDavid E. O'Brien t->t_dcdr->t_dflg |= t->t_dflg & 7499ccc37e3SMark Peek (F_NOFORK | F_NOINTERRUPT | F_BACKQ); 75029301572SMark Peek execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); 751c80476e4SDavid E. O'Brien } 752c80476e4SDavid E. O'Brien break; 753c80476e4SDavid E. O'Brien 754c80476e4SDavid E. O'Brien default: 755c80476e4SDavid E. O'Brien break; 756c80476e4SDavid E. O'Brien } 757c80476e4SDavid E. O'Brien /* 758c80476e4SDavid E. O'Brien * Fall through for all breaks from switch 759c80476e4SDavid E. O'Brien * 760c80476e4SDavid E. O'Brien * If there will be no more executions of this command, flush all file 761c80476e4SDavid E. O'Brien * descriptors. Places that turn on the F_REPEAT bit are responsible for 762c80476e4SDavid E. O'Brien * doing donefds after the last re-execution 763c80476e4SDavid E. O'Brien */ 764c80476e4SDavid E. O'Brien if (didfds && !(t->t_dflg & F_REPEAT)) 765c80476e4SDavid E. O'Brien donefds(); 766c80476e4SDavid E. O'Brien } 767c80476e4SDavid E. O'Brien 768c80476e4SDavid E. O'Brien #ifdef VFORK 76945e5710bSMark Peek static void 770c80476e4SDavid E. O'Brien /*ARGSUSED*/ 77145e5710bSMark Peek vffree(int snum) 772c80476e4SDavid E. O'Brien { 773c80476e4SDavid E. O'Brien USE(snum); 774c80476e4SDavid E. O'Brien 775c80476e4SDavid E. O'Brien _exit(1); 776c80476e4SDavid E. O'Brien } 777c80476e4SDavid E. O'Brien #endif /* VFORK */ 778c80476e4SDavid E. O'Brien 779c80476e4SDavid E. O'Brien /* 780c80476e4SDavid E. O'Brien * Expand and glob the words after an i/o redirection. 781c80476e4SDavid E. O'Brien * If more than one word is generated, then update the command vector. 782c80476e4SDavid E. O'Brien * 783c80476e4SDavid E. O'Brien * This is done differently in all the shells: 784c80476e4SDavid E. O'Brien * 1. in the bourne shell and ksh globbing is not performed 785c80476e4SDavid E. O'Brien * 2. Bash/csh say ambiguous 786c80476e4SDavid E. O'Brien * 3. zsh does i/o to/from all the files 787c80476e4SDavid E. O'Brien * 4. itcsh concatenates the words. 788c80476e4SDavid E. O'Brien * 789c80476e4SDavid E. O'Brien * I don't know what is best to do. I think that Ambiguous is better 790c80476e4SDavid E. O'Brien * than restructuring the command vector, because the user can get 791c80476e4SDavid E. O'Brien * unexpected results. In any case, the command vector restructuring 792c80476e4SDavid E. O'Brien * code is present and the user can choose it by setting noambiguous 793c80476e4SDavid E. O'Brien */ 794c80476e4SDavid E. O'Brien static Char * 79545e5710bSMark Peek splicepipe(struct command *t, Char *cp) 796c80476e4SDavid E. O'Brien { 797c80476e4SDavid E. O'Brien Char *blk[2]; 798c80476e4SDavid E. O'Brien 799c80476e4SDavid E. O'Brien if (adrof(STRnoambiguous)) { 800c80476e4SDavid E. O'Brien Char **pv; 80145e5710bSMark Peek int gflag; 802c80476e4SDavid E. O'Brien 803c80476e4SDavid E. O'Brien blk[0] = Dfix1(cp); /* expand $ */ 804c80476e4SDavid E. O'Brien blk[1] = NULL; 805c80476e4SDavid E. O'Brien 80645e5710bSMark Peek gflag = tglob(blk); 807c80476e4SDavid E. O'Brien if (gflag) { 80845e5710bSMark Peek pv = globall(blk, gflag); 809c80476e4SDavid E. O'Brien if (pv == NULL) { 810c80476e4SDavid E. O'Brien setname(short2str(blk[0])); 81145e5710bSMark Peek xfree(blk[0]); 812c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOMATCH); 813c80476e4SDavid E. O'Brien } 814c80476e4SDavid E. O'Brien if (pv[1] != NULL) { /* we need to fix the command vector */ 815c80476e4SDavid E. O'Brien Char **av = blkspl(t->t_dcom, &pv[1]); 81645e5710bSMark Peek xfree(t->t_dcom); 817c80476e4SDavid E. O'Brien t->t_dcom = av; 818c80476e4SDavid E. O'Brien } 81945e5710bSMark Peek xfree(blk[0]); 820c80476e4SDavid E. O'Brien blk[0] = pv[0]; 82145e5710bSMark Peek xfree(pv); 822c80476e4SDavid E. O'Brien } 823c80476e4SDavid E. O'Brien } 824c80476e4SDavid E. O'Brien else { 82545e5710bSMark Peek Char *buf; 826c80476e4SDavid E. O'Brien 82745e5710bSMark Peek buf = Dfix1(cp); 82845e5710bSMark Peek cleanup_push(buf, xfree); 829c80476e4SDavid E. O'Brien blk[0] = globone(buf, G_ERROR); 83045e5710bSMark Peek cleanup_until(buf); 831c80476e4SDavid E. O'Brien } 832c80476e4SDavid E. O'Brien return(blk[0]); 833c80476e4SDavid E. O'Brien } 834c80476e4SDavid E. O'Brien 835c80476e4SDavid E. O'Brien /* 836c80476e4SDavid E. O'Brien * Perform io redirection. 837c80476e4SDavid E. O'Brien * We may or maynot be forked here. 838c80476e4SDavid E. O'Brien */ 839c80476e4SDavid E. O'Brien static void 84045e5710bSMark Peek doio(struct command *t, int *pipein, int *pipeout) 841c80476e4SDavid E. O'Brien { 84223338178SMark Peek int fd; 84323338178SMark Peek Char *cp; 84423338178SMark Peek unsigned long flags = t->t_dflg; 845c80476e4SDavid E. O'Brien 846c80476e4SDavid E. O'Brien if (didfds || (flags & F_REPEAT)) 847c80476e4SDavid E. O'Brien return; 848c80476e4SDavid E. O'Brien if ((flags & F_READ) == 0) {/* F_READ already done */ 849c80476e4SDavid E. O'Brien if (t->t_dlef) { 85045e5710bSMark Peek char *tmp; 851c80476e4SDavid E. O'Brien 852c80476e4SDavid E. O'Brien /* 853c80476e4SDavid E. O'Brien * so < /dev/std{in,out,err} work 854c80476e4SDavid E. O'Brien */ 855c80476e4SDavid E. O'Brien (void) dcopy(SHIN, 0); 856c80476e4SDavid E. O'Brien (void) dcopy(SHOUT, 1); 857c80476e4SDavid E. O'Brien (void) dcopy(SHDIAG, 2); 858c80476e4SDavid E. O'Brien cp = splicepipe(t, t->t_dlef); 85945e5710bSMark Peek tmp = strsave(short2str(cp)); 86045e5710bSMark Peek xfree(cp); 86145e5710bSMark Peek cleanup_push(tmp, xfree); 86245e5710bSMark Peek if ((fd = xopen(tmp, O_RDONLY|O_LARGEFILE)) < 0) 863c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 86445e5710bSMark Peek cleanup_until(tmp); 865c80476e4SDavid E. O'Brien /* allow input files larger than 2Gb */ 866b2d5d167SMark Peek #ifndef WINNT_NATIVE 86723338178SMark Peek (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_LARGEFILE); 868b2d5d167SMark Peek #endif /*!WINNT_NATIVE*/ 869c80476e4SDavid E. O'Brien (void) dmove(fd, 0); 870c80476e4SDavid E. O'Brien } 871c80476e4SDavid E. O'Brien else if (flags & F_PIPEIN) { 87245e5710bSMark Peek xclose(0); 8739ccc37e3SMark Peek TCSH_IGNORE(dup(pipein[0])); 87445e5710bSMark Peek xclose(pipein[0]); 87545e5710bSMark Peek xclose(pipein[1]); 876c80476e4SDavid E. O'Brien } 877c80476e4SDavid E. O'Brien else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { 87845e5710bSMark Peek xclose(0); 87945e5710bSMark Peek (void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE); 880c80476e4SDavid E. O'Brien } 881c80476e4SDavid E. O'Brien else { 88245e5710bSMark Peek xclose(0); 8839ccc37e3SMark Peek TCSH_IGNORE(dup(OLDSTD)); 884c80476e4SDavid E. O'Brien #if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS) 885c80476e4SDavid E. O'Brien /* 886c80476e4SDavid E. O'Brien * PWP: Unlike Bezerkeley 4.3, FIONCLEX for Pyramid is preserved 887c80476e4SDavid E. O'Brien * across dup()s, so we have to UNSET it here or else we get a 888c80476e4SDavid E. O'Brien * command with NO stdin, stdout, or stderr at all (a bad thing 889c80476e4SDavid E. O'Brien * indeed) 890c80476e4SDavid E. O'Brien */ 891c80476e4SDavid E. O'Brien (void) close_on_exec(0, 0); 892c80476e4SDavid E. O'Brien #endif /* CLOSE_ON_EXEC && CLEX_DUPS */ 893c80476e4SDavid E. O'Brien } 894c80476e4SDavid E. O'Brien } 895c80476e4SDavid E. O'Brien if (t->t_drit) { 89645e5710bSMark Peek char *tmp; 897c80476e4SDavid E. O'Brien 898c80476e4SDavid E. O'Brien cp = splicepipe(t, t->t_drit); 89945e5710bSMark Peek tmp = strsave(short2str(cp)); 90045e5710bSMark Peek xfree(cp); 90145e5710bSMark Peek cleanup_push(tmp, xfree); 902c80476e4SDavid E. O'Brien /* 903c80476e4SDavid E. O'Brien * so > /dev/std{out,err} work 904c80476e4SDavid E. O'Brien */ 905c80476e4SDavid E. O'Brien (void) dcopy(SHOUT, 1); 906c80476e4SDavid E. O'Brien (void) dcopy(SHDIAG, 2); 907c80476e4SDavid E. O'Brien if ((flags & F_APPEND) != 0) { 908c80476e4SDavid E. O'Brien #ifdef O_APPEND 90945e5710bSMark Peek fd = xopen(tmp, O_WRONLY|O_APPEND|O_LARGEFILE); 910c80476e4SDavid E. O'Brien #else /* !O_APPEND */ 91145e5710bSMark Peek fd = xopen(tmp, O_WRONLY|O_LARGEFILE); 912c80476e4SDavid E. O'Brien (void) lseek(fd, (off_t) 0, L_XTND); 913c80476e4SDavid E. O'Brien #endif /* O_APPEND */ 914c80476e4SDavid E. O'Brien } 915c80476e4SDavid E. O'Brien else 916c80476e4SDavid E. O'Brien fd = 0; 917c80476e4SDavid E. O'Brien if ((flags & F_APPEND) == 0 || fd == -1) { 918*19d2e3deSDmitry Chagin if (!(flags & F_OVERWRITE) && no_clobber) { 919c80476e4SDavid E. O'Brien if (flags & F_APPEND) 920c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 921c80476e4SDavid E. O'Brien chkclob(tmp); 922c80476e4SDavid E. O'Brien } 92345e5710bSMark Peek if ((fd = xcreat(tmp, 0666)) < 0) 924c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 925c80476e4SDavid E. O'Brien /* allow input files larger than 2Gb */ 926b2d5d167SMark Peek #ifndef WINNT_NATIVE 92723338178SMark Peek (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_LARGEFILE); 928b2d5d167SMark Peek #endif /*!WINNT_NATIVE*/ 929c80476e4SDavid E. O'Brien } 93045e5710bSMark Peek cleanup_until(tmp); 931c80476e4SDavid E. O'Brien (void) dmove(fd, 1); 932c80476e4SDavid E. O'Brien is1atty = isatty(1); 933c80476e4SDavid E. O'Brien } 934c80476e4SDavid E. O'Brien else if (flags & F_PIPEOUT) { 93545e5710bSMark Peek xclose(1); 9369ccc37e3SMark Peek TCSH_IGNORE(dup(pipeout[1])); 937c80476e4SDavid E. O'Brien is1atty = 0; 938c80476e4SDavid E. O'Brien } 939c80476e4SDavid E. O'Brien else { 94045e5710bSMark Peek xclose(1); 9419ccc37e3SMark Peek TCSH_IGNORE(dup(SHOUT)); 942c80476e4SDavid E. O'Brien is1atty = isoutatty; 943c80476e4SDavid E. O'Brien # if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS) 944c80476e4SDavid E. O'Brien (void) close_on_exec(1, 0); 945c80476e4SDavid E. O'Brien # endif /* CLOSE_ON_EXEC && CLEX_DUPS */ 946c80476e4SDavid E. O'Brien } 947c80476e4SDavid E. O'Brien 94845e5710bSMark Peek xclose(2); 949c80476e4SDavid E. O'Brien if (flags & F_STDERR) { 9509ccc37e3SMark Peek TCSH_IGNORE(dup(1)); 951c80476e4SDavid E. O'Brien is2atty = is1atty; 952c80476e4SDavid E. O'Brien } 953c80476e4SDavid E. O'Brien else { 9549ccc37e3SMark Peek TCSH_IGNORE(dup(SHDIAG)); 955c80476e4SDavid E. O'Brien is2atty = isdiagatty; 956c80476e4SDavid E. O'Brien # if defined(CLOSE_ON_EXEC) && defined(CLEX_DUPS) 957c80476e4SDavid E. O'Brien (void) close_on_exec(2, 0); 958c80476e4SDavid E. O'Brien # endif /* CLOSE_ON_EXEC && CLEX_DUPS */ 959c80476e4SDavid E. O'Brien } 960c80476e4SDavid E. O'Brien didfds = 1; 961c80476e4SDavid E. O'Brien } 962c80476e4SDavid E. O'Brien 963c80476e4SDavid E. O'Brien void 96445e5710bSMark Peek mypipe(int *pv) 965c80476e4SDavid E. O'Brien { 966c80476e4SDavid E. O'Brien 967c80476e4SDavid E. O'Brien if (pipe(pv) < 0) 968c80476e4SDavid E. O'Brien goto oops; 96923338178SMark Peek (void)close_on_exec(pv[0] = dmove(pv[0], -1), 1); 97023338178SMark Peek (void)close_on_exec(pv[1] = dmove(pv[1], -1), 1); 971c80476e4SDavid E. O'Brien if (pv[0] >= 0 && pv[1] >= 0) 972c80476e4SDavid E. O'Brien return; 97345e5710bSMark Peek if (pv[0] >= 0) 97445e5710bSMark Peek xclose(pv[0]); 97545e5710bSMark Peek if (pv[1] >= 0) 97645e5710bSMark Peek xclose(pv[1]); 977c80476e4SDavid E. O'Brien oops: 978c80476e4SDavid E. O'Brien stderror(ERR_PIPE); 979c80476e4SDavid E. O'Brien } 980c80476e4SDavid E. O'Brien 981c80476e4SDavid E. O'Brien static void 98245e5710bSMark Peek chkclob(const char *cp) 983c80476e4SDavid E. O'Brien { 984c80476e4SDavid E. O'Brien struct stat stb; 985c80476e4SDavid E. O'Brien 986c80476e4SDavid E. O'Brien if (stat(cp, &stb) < 0) 987c80476e4SDavid E. O'Brien return; 988c80476e4SDavid E. O'Brien if (S_ISCHR(stb.st_mode)) 989c80476e4SDavid E. O'Brien return; 990*19d2e3deSDmitry Chagin if (no_clobber & NOCLOBBER_NOTEMPTY && stb.st_size == 0) 991*19d2e3deSDmitry Chagin return; 992*19d2e3deSDmitry Chagin if (no_clobber & NOCLOBBER_ASK) { 993*19d2e3deSDmitry Chagin if (getYN(CGETS(22, 15, 994*19d2e3deSDmitry Chagin "Do you really want to overwrite an existing file? [N/y] "))) 995*19d2e3deSDmitry Chagin return; 996*19d2e3deSDmitry Chagin } 997*19d2e3deSDmitry Chagin 998c80476e4SDavid E. O'Brien stderror(ERR_EXISTS, cp); 999c80476e4SDavid E. O'Brien } 1000