1*d6fabe6eSbostic /*- 2*d6fabe6eSbostic * Copyright (c) 1980, 1991 The Regents of the University of California. 3*d6fabe6eSbostic * All rights reserved. 4*d6fabe6eSbostic * 5*d6fabe6eSbostic * %sccs.include.redist.c% 6c1549ed3Sdist */ 7c1549ed3Sdist 843fabe3fSedward #ifndef lint 9*d6fabe6eSbostic static char sccsid[] = "@(#)sem.c 5.11 (Berkeley) 04/04/91"; 10*d6fabe6eSbostic #endif /* not lint */ 1113082428Sbill 1213082428Sbill #include "sh.h" 1313082428Sbill #include "sh.proc.h" 147b1c9148Smckusick #include <sys/file.h> 1513082428Sbill #include <sys/ioctl.h> 165e5c7fccSmarc #include "pathnames.h" 1713082428Sbill 1813082428Sbill /* 1913082428Sbill * C shell 2013082428Sbill */ 2113082428Sbill 225e5c7fccSmarc static int nosigchld = 0, osigmask; 235e5c7fccSmarc static int onosigchld = 0, oosigmask; 2413082428Sbill /*VARARGS 1*/ 2513082428Sbill execute(t, wanttty, pipein, pipeout) 2613082428Sbill register struct command *t; 2713082428Sbill int wanttty, *pipein, *pipeout; 2813082428Sbill { 2913082428Sbill bool forked = 0; 3013082428Sbill struct biltins *bifunc; 3113082428Sbill int pid = 0; 3213082428Sbill int pv[2]; 3313082428Sbill 3413082428Sbill if (t == 0) 3513082428Sbill return; 365eb3278cSbostic if ((t->t_dflg & F_AMPERSAND) && wanttty > 0) 3713082428Sbill wanttty = 0; 3813082428Sbill switch (t->t_dtyp) { 3913082428Sbill 405eb3278cSbostic case NODE_COMMAND: 4113082428Sbill if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE) 4243fabe3fSedward (void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1); 435eb3278cSbostic if ((t->t_dflg & F_REPEAT) == 0) 4413082428Sbill Dfix(t); /* $ " ' \ */ 4513082428Sbill if (t->t_dcom[0] == 0) 4613082428Sbill return; 4713082428Sbill /* fall into... */ 4813082428Sbill 495eb3278cSbostic case NODE_PAREN: 505eb3278cSbostic if (t->t_dflg & F_PIPEOUT) 5113082428Sbill mypipe(pipeout); 5213082428Sbill /* 5313082428Sbill * Must do << early so parent will know 5413082428Sbill * where input pointer should be. 5513082428Sbill * If noexec then this is all we do. 5613082428Sbill */ 575eb3278cSbostic if (t->t_dflg & F_READ) { 5843fabe3fSedward (void) close(0); 5913082428Sbill heredoc(t->t_dlef); 6013082428Sbill if (noexec) 6143fabe3fSedward (void) close(0); 6213082428Sbill } 6313082428Sbill if (noexec) 6413082428Sbill break; 6513082428Sbill 6613082428Sbill set("status", "0"); 6713082428Sbill 6813082428Sbill /* 6913082428Sbill * This mess is the necessary kludge to handle the prefix 7013082428Sbill * builtins: nice, nohup, time. These commands can also 7113082428Sbill * be used by themselves, and this is not handled here. 7213082428Sbill * This will also work when loops are parsed. 7313082428Sbill */ 745eb3278cSbostic while (t->t_dtyp == NODE_COMMAND) 7513082428Sbill if (eq(t->t_dcom[0], "nice")) 7613082428Sbill if (t->t_dcom[1]) 776f545c8fSbostic if (index("+-", t->t_dcom[1][0])) 7813082428Sbill if (t->t_dcom[2]) { 7913082428Sbill setname("nice"); 8013082428Sbill t->t_nice = getn(t->t_dcom[1]); 8113082428Sbill lshift(t->t_dcom, 2); 825eb3278cSbostic t->t_dflg |= F_NICE; 8313082428Sbill } else 8413082428Sbill break; 8513082428Sbill else { 8613082428Sbill t->t_nice = 4; 8713082428Sbill lshift(t->t_dcom, 1); 885eb3278cSbostic t->t_dflg |= F_NICE; 8913082428Sbill } 9013082428Sbill else 9113082428Sbill break; 9213082428Sbill else if (eq(t->t_dcom[0], "nohup")) 9313082428Sbill if (t->t_dcom[1]) { 945eb3278cSbostic t->t_dflg |= F_NOHUP; 9513082428Sbill lshift(t->t_dcom, 1); 9613082428Sbill } else 9713082428Sbill break; 9813082428Sbill else if (eq(t->t_dcom[0], "time")) 9913082428Sbill if (t->t_dcom[1]) { 1005eb3278cSbostic t->t_dflg |= F_TIME; 10113082428Sbill lshift(t->t_dcom, 1); 10213082428Sbill } else 10313082428Sbill break; 10413082428Sbill else 10513082428Sbill break; 10613082428Sbill /* 10713082428Sbill * Check if we have a builtin function and remember which one. 10813082428Sbill */ 1095eb3278cSbostic bifunc = t->t_dtyp == 1105eb3278cSbostic NODE_COMMAND ? isbfunc(t) : (struct biltins *) 0; 11113082428Sbill 11213082428Sbill /* 11313082428Sbill * We fork only if we are timed, or are not the end of 11413082428Sbill * a parenthesized list and not a simple builtin function. 11513082428Sbill * Simple meaning one that is not pipedout, niced, nohupped, 11613082428Sbill * or &'d. 11713082428Sbill * It would be nice(?) to not fork in some of these cases. 11813082428Sbill */ 1195eb3278cSbostic if (((t->t_dflg & F_TIME) || (t->t_dflg & F_NOFORK) == 0 && 1205eb3278cSbostic (!bifunc || 1215eb3278cSbostic t->t_dflg & (F_PIPEOUT|F_AMPERSAND|F_NICE|F_NOHUP)))) 12213082428Sbill #ifdef VFORK 1235eb3278cSbostic if (t->t_dtyp == NODE_PAREN || 1245eb3278cSbostic t->t_dflg&(F_REPEAT|F_AMPERSAND) || bifunc) 12513082428Sbill #endif 1265e5c7fccSmarc { forked++; 1275e5c7fccSmarc if (wanttty >= 0 && !nosigchld) { 1285e5c7fccSmarc osigmask = sigblock(sigmask(SIGCHLD)); 1295e5c7fccSmarc nosigchld = 1; 1305e5c7fccSmarc } 1315e5c7fccSmarc 1325e5c7fccSmarc pid = pfork(t, wanttty); 1335e5c7fccSmarc if (pid == 0 && nosigchld) { 1345e5c7fccSmarc sigsetmask(osigmask); 1355e5c7fccSmarc nosigchld = 0; 1365e5c7fccSmarc } 1375e5c7fccSmarc } 13813082428Sbill #ifdef VFORK 13913082428Sbill else { 1405e5c7fccSmarc sig_t vffree; 14143fabe3fSedward int ochild, osetintr, ohaderr, odidfds; 14213082428Sbill int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; 1433bb023eaSbostic long omask; 14413082428Sbill 14515d9e91aSlepreau /* 14615d9e91aSlepreau * Prepare for the vfork by saving everything 14715d9e91aSlepreau * that the child corrupts before it exec's. 14815d9e91aSlepreau * Note that in some signal implementations 14915d9e91aSlepreau * which keep the signal info in user space 15015d9e91aSlepreau * (e.g. Sun's) it will also be necessary to 15115d9e91aSlepreau * save and restore the current sigvec's for 15215d9e91aSlepreau * the signals the child touches before it 15315d9e91aSlepreau * exec's. 15415d9e91aSlepreau */ 1555e5c7fccSmarc if (wanttty >= 0 && !nosigchld && !noexec) { 1565e5c7fccSmarc osigmask = sigblock(sigmask(SIGCHLD)); 1575e5c7fccSmarc nosigchld = 1; 1585e5c7fccSmarc } 1591e9806efSralph omask = sigblock(sigmask(SIGCHLD)); 16013082428Sbill ochild = child; osetintr = setintr; 16143fabe3fSedward ohaderr = haderr; odidfds = didfds; 16213082428Sbill oSHIN = SHIN; oSHOUT = SHOUT; 16313082428Sbill oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; 1645e5c7fccSmarc oosigmask = osigmask; onosigchld = nosigchld; 16513082428Sbill Vsav = Vdp = 0; Vav = 0; 16613082428Sbill pid = vfork(); 16713082428Sbill if (pid < 0) { 16843fabe3fSedward (void) sigsetmask(omask); 16913082428Sbill error("No more processes"); 17013082428Sbill } 17113082428Sbill forked++; 17215d9e91aSlepreau if (pid) { /* parent */ 17313082428Sbill child = ochild; setintr = osetintr; 17413082428Sbill haderr = ohaderr; didfds = odidfds; 17543fabe3fSedward SHIN = oSHIN; 17613082428Sbill SHOUT = oSHOUT; SHDIAG = oSHDIAG; 17713082428Sbill OLDSTD = oOLDSTD; tpgrp = otpgrp; 1785e5c7fccSmarc osigmask = oosigmask; nosigchld = onosigchld; 17913082428Sbill xfree(Vsav); Vsav = 0; 18013082428Sbill xfree(Vdp); Vdp = 0; 18143fabe3fSedward xfree((char *)Vav); Vav = 0; 18213082428Sbill /* this is from pfork() */ 18313082428Sbill palloc(pid, t); 18443fabe3fSedward (void) sigsetmask(omask); 18515d9e91aSlepreau } else { /* child */ 18613082428Sbill /* this is from pfork() */ 18713082428Sbill int pgrp; 18813082428Sbill bool ignint = 0; 18913082428Sbill 1905e5c7fccSmarc if (nosigchld) { 1915e5c7fccSmarc sigsetmask(osigmask); 1925e5c7fccSmarc nosigchld = 0; 1935e5c7fccSmarc } 19413082428Sbill if (setintr) 1955eb3278cSbostic ignint = (tpgrp == -1 && 1965eb3278cSbostic (t->t_dflg&F_NOINTERRUPT)) || 1975eb3278cSbostic gointr && eq(gointr, "-"); 19813082428Sbill pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 19913082428Sbill child++; 20013082428Sbill if (setintr) { 20113082428Sbill setintr = 0; 2022c8ae23aSsam #ifdef notdef 20343fabe3fSedward (void) signal(SIGCHLD, SIG_DFL); 2042c8ae23aSsam #endif 20543fabe3fSedward (void) signal(SIGINT, ignint ? 2061e9806efSralph SIG_IGN : vffree); 20743fabe3fSedward (void) signal(SIGQUIT, ignint ? 2081e9806efSralph SIG_IGN : SIG_DFL); 20913082428Sbill if (wanttty >= 0) { 21043fabe3fSedward (void) signal(SIGTSTP, SIG_DFL); 21143fabe3fSedward (void) signal(SIGTTIN, SIG_DFL); 21243fabe3fSedward (void) signal(SIGTTOU, SIG_DFL); 21313082428Sbill } 21443fabe3fSedward (void) signal(SIGTERM, parterm); 2155eb3278cSbostic } else if (tpgrp == -1 && 2165eb3278cSbostic (t->t_dflg&F_NOINTERRUPT)) { 21743fabe3fSedward (void) signal(SIGINT, SIG_IGN); 21843fabe3fSedward (void) signal(SIGQUIT, SIG_IGN); 21913082428Sbill } 2205e5c7fccSmarc if (wanttty >= 0 && tpgrp >= 0) 2215e5c7fccSmarc (void) setpgrp(0, pgrp); 22213082428Sbill if (wanttty > 0) 22343fabe3fSedward (void) ioctl(FSHTTY, TIOCSPGRP, 22443fabe3fSedward (char *)&pgrp); 22513082428Sbill if (tpgrp > 0) 22613082428Sbill tpgrp = 0; 2275eb3278cSbostic if (t->t_dflg & F_NOHUP) 22843fabe3fSedward (void) signal(SIGHUP, SIG_IGN); 2295eb3278cSbostic if (t->t_dflg & F_NICE) 23015d9e91aSlepreau (void) setpriority(PRIO_PROCESS, 23115d9e91aSlepreau 0, t->t_nice); 23213082428Sbill } 23313082428Sbill 23413082428Sbill } 23513082428Sbill #endif 23613082428Sbill if (pid != 0) { 23713082428Sbill /* 23813082428Sbill * It would be better if we could wait for the 23913082428Sbill * whole job when we knew the last process 24013082428Sbill * had been started. Pwait, in fact, does 24113082428Sbill * wait for the whole job anyway, but this test 24213082428Sbill * doesn't really express our intentions. 24313082428Sbill */ 2445eb3278cSbostic if (didfds==0 && t->t_dflg&F_PIPEIN) { 24543fabe3fSedward (void) close(pipein[0]); 24643fabe3fSedward (void) close(pipein[1]); 24743fabe3fSedward } 2485eb3278cSbostic if ((t->t_dflg & F_PIPEOUT) == 0) { 2495e5c7fccSmarc if (nosigchld) { 2505e5c7fccSmarc #ifdef foobarbaz 2515e5c7fccSmarc printf("DID\n"); 2525e5c7fccSmarc #endif 2535e5c7fccSmarc sigsetmask(osigmask); 2545e5c7fccSmarc nosigchld = 0; 2555e5c7fccSmarc } 2565eb3278cSbostic if ((t->t_dflg & F_AMPERSAND) == 0) 25713082428Sbill pwait(); 2585e5c7fccSmarc } 25913082428Sbill break; 26013082428Sbill } 26113082428Sbill doio(t, pipein, pipeout); 2625eb3278cSbostic if (t->t_dflg & F_PIPEOUT) { 26343fabe3fSedward (void) close(pipeout[0]); 26443fabe3fSedward (void) close(pipeout[1]); 26543fabe3fSedward } 26613082428Sbill 26713082428Sbill /* 26813082428Sbill * Perform a builtin function. 26913082428Sbill * If we are not forked, arrange for possible stopping 27013082428Sbill */ 27113082428Sbill if (bifunc) { 27213082428Sbill func(t, bifunc); 27313082428Sbill if (forked) 27413082428Sbill exitstat(); 27513082428Sbill break; 27613082428Sbill } 2775eb3278cSbostic if (t->t_dtyp != NODE_PAREN) { 27813082428Sbill doexec(t); 27913082428Sbill /*NOTREACHED*/ 28013082428Sbill } 28113082428Sbill /* 28213082428Sbill * For () commands must put new 0,1,2 in FSH* and recurse 28313082428Sbill */ 28413082428Sbill OLDSTD = dcopy(0, FOLDSTD); 28513082428Sbill SHOUT = dcopy(1, FSHOUT); 28613082428Sbill SHDIAG = dcopy(2, FSHDIAG); 28743fabe3fSedward (void) close(SHIN); 28843fabe3fSedward SHIN = -1; 28943fabe3fSedward didfds = 0; 29013082428Sbill wanttty = -1; 2915eb3278cSbostic t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; 29213082428Sbill execute(t->t_dspr, wanttty); 29313082428Sbill exitstat(); 29413082428Sbill 2955eb3278cSbostic case NODE_PIPE: 2965eb3278cSbostic t->t_dcar->t_dflg |= F_PIPEOUT | 2975eb3278cSbostic (t->t_dflg & (F_PIPEIN|F_AMPERSAND|F_STDERR|F_NOINTERRUPT)); 29813082428Sbill execute(t->t_dcar, wanttty, pipein, pv); 2995eb3278cSbostic t->t_dcdr->t_dflg |= F_PIPEIN | 3005eb3278cSbostic (t->t_dflg & 3015eb3278cSbostic (F_PIPEOUT|F_AMPERSAND|F_NOFORK|F_NOINTERRUPT)); 30213082428Sbill if (wanttty > 0) 30313082428Sbill wanttty = 0; /* got tty already */ 30413082428Sbill execute(t->t_dcdr, wanttty, pv, pipeout); 30513082428Sbill break; 30613082428Sbill 3075eb3278cSbostic case NODE_LIST: 30813082428Sbill if (t->t_dcar) { 3095eb3278cSbostic t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 31013082428Sbill execute(t->t_dcar, wanttty); 31113082428Sbill /* 31213082428Sbill * In strange case of A&B make a new job after A 31313082428Sbill */ 3145eb3278cSbostic if (t->t_dcar->t_dflg&F_AMPERSAND && t->t_dcdr && 3155eb3278cSbostic (t->t_dcdr->t_dflg&F_AMPERSAND) == 0) 31613082428Sbill pendjob(); 31713082428Sbill } 31813082428Sbill if (t->t_dcdr) { 3195eb3278cSbostic t->t_dcdr->t_dflg |= 3205eb3278cSbostic t->t_dflg & (F_NOFORK|F_NOINTERRUPT); 32113082428Sbill execute(t->t_dcdr, wanttty); 32213082428Sbill } 32313082428Sbill break; 32413082428Sbill 3255eb3278cSbostic case NODE_OR: 3265eb3278cSbostic case NODE_AND: 32713082428Sbill if (t->t_dcar) { 3285eb3278cSbostic t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 32913082428Sbill execute(t->t_dcar, wanttty); 3305eb3278cSbostic if ((getn(value("status")) == 0) != 3315eb3278cSbostic (t->t_dtyp == NODE_AND)) 33213082428Sbill return; 33313082428Sbill } 33413082428Sbill if (t->t_dcdr) { 3355eb3278cSbostic t->t_dcdr->t_dflg |= 3365eb3278cSbostic t->t_dflg & (F_NOFORK|F_NOINTERRUPT); 33713082428Sbill execute(t->t_dcdr, wanttty); 33813082428Sbill } 33913082428Sbill break; 34013082428Sbill } 34113082428Sbill /* 3425eb3278cSbostic * Fall through for all breaks from switch. 34313082428Sbill * 3445eb3278cSbostic * If there will be no more executions of this command, flush all 3455eb3278cSbostic * file descriptors. Places that turn on the F_REPEAT bit are 3465eb3278cSbostic * responsible for doing donefds after the last re-execution 34713082428Sbill */ 3485eb3278cSbostic if (didfds && !(t->t_dflg & F_REPEAT)) 34913082428Sbill donefds(); 35013082428Sbill } 35113082428Sbill 35213082428Sbill #ifdef VFORK 35313082428Sbill vffree() 35413082428Sbill { 35513082428Sbill register char **v; 35613082428Sbill 35713082428Sbill if (v = gargv) 35843fabe3fSedward gargv = 0, xfree((char *)v); 35913082428Sbill if (v = pargv) 36043fabe3fSedward pargv = 0, xfree((char *)v); 36113082428Sbill _exit(1); 36213082428Sbill } 36313082428Sbill #endif 36413082428Sbill 36513082428Sbill /* 36613082428Sbill * Perform io redirection. 36713082428Sbill * We may or maynot be forked here. 36813082428Sbill */ 36913082428Sbill doio(t, pipein, pipeout) 37013082428Sbill register struct command *t; 37113082428Sbill int *pipein, *pipeout; 37213082428Sbill { 37313082428Sbill register char *cp; 37413082428Sbill register int flags = t->t_dflg; 37513082428Sbill 3765eb3278cSbostic if (didfds || (flags & F_REPEAT)) 37713082428Sbill return; 3785eb3278cSbostic if ((flags & F_READ) == 0) { /* F_READ already done */ 37943fabe3fSedward (void) close(0); 38013082428Sbill if (cp = t->t_dlef) { 38113082428Sbill cp = globone(Dfix1(cp)); 38213082428Sbill xfree(cp); 38313082428Sbill if (open(cp, 0) < 0) 38413082428Sbill Perror(cp); 3855eb3278cSbostic } else if (flags & F_PIPEIN) { 38643fabe3fSedward (void) dup(pipein[0]); 38743fabe3fSedward (void) close(pipein[0]); 38843fabe3fSedward (void) close(pipein[1]); 3895eb3278cSbostic } else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { 39043fabe3fSedward (void) close(0); 3915e5c7fccSmarc (void) open(_PATH_DEVNULL, 0); 39243fabe3fSedward } else 393cde959b4Sedward (void) dup(OLDSTD); 39413082428Sbill } 39543fabe3fSedward (void) close(1); 39613082428Sbill if (cp = t->t_drit) { 39713082428Sbill cp = globone(Dfix1(cp)); 39813082428Sbill xfree(cp); 3995eb3278cSbostic if (!(flags & F_APPEND) || open(cp, O_WRONLY|O_APPEND, 0) < 0) { 4005eb3278cSbostic if (!(flags & F_OVERWRITE) && adrof("noclobber")) { 4015eb3278cSbostic if (flags & F_APPEND) 40213082428Sbill Perror(cp); 40313082428Sbill chkclob(cp); 40413082428Sbill } 40513082428Sbill if (creat(cp, 0666) < 0) 40613082428Sbill Perror(cp); 40713082428Sbill } 4085eb3278cSbostic } else if (flags & F_PIPEOUT) 40943fabe3fSedward (void) dup(pipeout[1]); 41013082428Sbill else 411cde959b4Sedward (void) dup(SHOUT); 41213082428Sbill 41343fabe3fSedward (void) close(2); 4145eb3278cSbostic if (flags & F_STDERR) 41543fabe3fSedward (void) dup(1); 41643fabe3fSedward else 417cde959b4Sedward (void) dup(SHDIAG); 41813082428Sbill didfds = 1; 41913082428Sbill } 42013082428Sbill 42113082428Sbill mypipe(pv) 42213082428Sbill register int *pv; 42313082428Sbill { 42413082428Sbill 42513082428Sbill if (pipe(pv) < 0) 42613082428Sbill goto oops; 42713082428Sbill pv[0] = dmove(pv[0], -1); 42813082428Sbill pv[1] = dmove(pv[1], -1); 42913082428Sbill if (pv[0] >= 0 && pv[1] >= 0) 43013082428Sbill return; 43113082428Sbill oops: 43213082428Sbill error("Can't make pipe"); 43313082428Sbill } 43413082428Sbill 43513082428Sbill chkclob(cp) 43613082428Sbill register char *cp; 43713082428Sbill { 43813082428Sbill struct stat stb; 43913082428Sbill 44013082428Sbill if (stat(cp, &stb) < 0) 44113082428Sbill return; 44213082428Sbill if ((stb.st_mode & S_IFMT) == S_IFCHR) 44313082428Sbill return; 44413082428Sbill error("%s: File exists", cp); 44513082428Sbill } 446