1*c1549ed3Sdist /* 2*c1549ed3Sdist * Copyright (c) 1980 Regents of the University of California. 3*c1549ed3Sdist * All rights reserved. The Berkeley software License Agreement 4*c1549ed3Sdist * specifies the terms and conditions for redistribution. 5*c1549ed3Sdist */ 6*c1549ed3Sdist 743fabe3fSedward #ifndef lint 8*c1549ed3Sdist static char sccsid[] = "@(#)sem.c 5.1 (Berkeley) 06/04/85"; 9*c1549ed3Sdist #endif not lint 1013082428Sbill 1113082428Sbill #include "sh.h" 1213082428Sbill #include "sh.proc.h" 1313082428Sbill #include <sys/ioctl.h> 1413082428Sbill 1513082428Sbill /* 1613082428Sbill * C shell 1713082428Sbill */ 1813082428Sbill 1913082428Sbill /*VARARGS 1*/ 2013082428Sbill execute(t, wanttty, pipein, pipeout) 2113082428Sbill register struct command *t; 2213082428Sbill int wanttty, *pipein, *pipeout; 2313082428Sbill { 2413082428Sbill bool forked = 0; 2513082428Sbill struct biltins *bifunc; 2613082428Sbill int pid = 0; 2713082428Sbill int pv[2]; 2813082428Sbill 2913082428Sbill if (t == 0) 3013082428Sbill return; 3113082428Sbill if ((t->t_dflg & FAND) && wanttty > 0) 3213082428Sbill wanttty = 0; 3313082428Sbill switch (t->t_dtyp) { 3413082428Sbill 3513082428Sbill case TCOM: 3613082428Sbill if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE) 3743fabe3fSedward (void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1); 3813082428Sbill if ((t->t_dflg & FREDO) == 0) 3913082428Sbill Dfix(t); /* $ " ' \ */ 4013082428Sbill if (t->t_dcom[0] == 0) 4113082428Sbill return; 4213082428Sbill /* fall into... */ 4313082428Sbill 4413082428Sbill case TPAR: 4513082428Sbill if (t->t_dflg & FPOU) 4613082428Sbill mypipe(pipeout); 4713082428Sbill /* 4813082428Sbill * Must do << early so parent will know 4913082428Sbill * where input pointer should be. 5013082428Sbill * If noexec then this is all we do. 5113082428Sbill */ 5213082428Sbill if (t->t_dflg & FHERE) { 5343fabe3fSedward (void) close(0); 5413082428Sbill heredoc(t->t_dlef); 5513082428Sbill if (noexec) 5643fabe3fSedward (void) close(0); 5713082428Sbill } 5813082428Sbill if (noexec) 5913082428Sbill break; 6013082428Sbill 6113082428Sbill set("status", "0"); 6213082428Sbill 6313082428Sbill /* 6413082428Sbill * This mess is the necessary kludge to handle the prefix 6513082428Sbill * builtins: nice, nohup, time. These commands can also 6613082428Sbill * be used by themselves, and this is not handled here. 6713082428Sbill * This will also work when loops are parsed. 6813082428Sbill */ 6913082428Sbill while (t->t_dtyp == TCOM) 7013082428Sbill if (eq(t->t_dcom[0], "nice")) 7113082428Sbill if (t->t_dcom[1]) 7213082428Sbill if (any(t->t_dcom[1][0], "+-")) 7313082428Sbill if (t->t_dcom[2]) { 7413082428Sbill setname("nice"); 7513082428Sbill t->t_nice = getn(t->t_dcom[1]); 7613082428Sbill lshift(t->t_dcom, 2); 7713082428Sbill t->t_dflg |= FNICE; 7813082428Sbill } else 7913082428Sbill break; 8013082428Sbill else { 8113082428Sbill t->t_nice = 4; 8213082428Sbill lshift(t->t_dcom, 1); 8313082428Sbill t->t_dflg |= FNICE; 8413082428Sbill } 8513082428Sbill else 8613082428Sbill break; 8713082428Sbill else if (eq(t->t_dcom[0], "nohup")) 8813082428Sbill if (t->t_dcom[1]) { 8913082428Sbill t->t_dflg |= FNOHUP; 9013082428Sbill lshift(t->t_dcom, 1); 9113082428Sbill } else 9213082428Sbill break; 9313082428Sbill else if (eq(t->t_dcom[0], "time")) 9413082428Sbill if (t->t_dcom[1]) { 9513082428Sbill t->t_dflg |= FTIME; 9613082428Sbill lshift(t->t_dcom, 1); 9713082428Sbill } else 9813082428Sbill break; 9913082428Sbill else 10013082428Sbill break; 10113082428Sbill /* 10213082428Sbill * Check if we have a builtin function and remember which one. 10313082428Sbill */ 10413082428Sbill bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0; 10513082428Sbill 10613082428Sbill /* 10713082428Sbill * We fork only if we are timed, or are not the end of 10813082428Sbill * a parenthesized list and not a simple builtin function. 10913082428Sbill * Simple meaning one that is not pipedout, niced, nohupped, 11013082428Sbill * or &'d. 11113082428Sbill * It would be nice(?) to not fork in some of these cases. 11213082428Sbill */ 11313082428Sbill if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 && 11413082428Sbill (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP)))) 11513082428Sbill #ifdef VFORK 11613082428Sbill if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc) 11713082428Sbill #endif 11813082428Sbill { forked++; pid = pfork(t, wanttty); } 11913082428Sbill #ifdef VFORK 12013082428Sbill else { 12113082428Sbill int vffree(); 12243fabe3fSedward int ochild, osetintr, ohaderr, odidfds; 12313082428Sbill int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; 1241e9806efSralph int omask; 12513082428Sbill 1261e9806efSralph omask = sigblock(sigmask(SIGCHLD)); 12713082428Sbill ochild = child; osetintr = setintr; 12843fabe3fSedward ohaderr = haderr; odidfds = didfds; 12913082428Sbill oSHIN = SHIN; oSHOUT = SHOUT; 13013082428Sbill oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; 13113082428Sbill Vsav = Vdp = 0; Vav = 0; 13213082428Sbill pid = vfork(); 13313082428Sbill if (pid < 0) { 13443fabe3fSedward (void) sigsetmask(omask); 13513082428Sbill error("No more processes"); 13613082428Sbill } 13713082428Sbill forked++; 13813082428Sbill if (pid) { 13913082428Sbill child = ochild; setintr = osetintr; 14013082428Sbill haderr = ohaderr; didfds = odidfds; 14143fabe3fSedward SHIN = oSHIN; 14213082428Sbill SHOUT = oSHOUT; SHDIAG = oSHDIAG; 14313082428Sbill OLDSTD = oOLDSTD; tpgrp = otpgrp; 14413082428Sbill xfree(Vsav); Vsav = 0; 14513082428Sbill xfree(Vdp); Vdp = 0; 14643fabe3fSedward xfree((char *)Vav); Vav = 0; 14713082428Sbill /* this is from pfork() */ 14813082428Sbill palloc(pid, t); 14943fabe3fSedward (void) sigsetmask(omask); 15013082428Sbill } else { 15113082428Sbill /* this is from pfork() */ 15213082428Sbill int pgrp; 15313082428Sbill bool ignint = 0; 15413082428Sbill 15513082428Sbill if (setintr) 15613082428Sbill ignint = 15713082428Sbill (tpgrp == -1 && (t->t_dflg&FINT)) 15813082428Sbill || gointr && eq(gointr, "-"); 15913082428Sbill pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 16013082428Sbill child++; 16113082428Sbill if (setintr) { 16213082428Sbill setintr = 0; 1632c8ae23aSsam #ifdef notdef 16443fabe3fSedward (void) signal(SIGCHLD, SIG_DFL); 1652c8ae23aSsam #endif 16643fabe3fSedward (void) signal(SIGINT, ignint ? 1671e9806efSralph SIG_IGN : vffree); 16843fabe3fSedward (void) signal(SIGQUIT, ignint ? 1691e9806efSralph SIG_IGN : SIG_DFL); 17013082428Sbill if (wanttty >= 0) { 17143fabe3fSedward (void) signal(SIGTSTP, SIG_DFL); 17243fabe3fSedward (void) signal(SIGTTIN, SIG_DFL); 17343fabe3fSedward (void) signal(SIGTTOU, SIG_DFL); 17413082428Sbill } 17543fabe3fSedward (void) signal(SIGTERM, parterm); 17613082428Sbill } else if (tpgrp == -1 && (t->t_dflg&FINT)) { 17743fabe3fSedward (void) signal(SIGINT, SIG_IGN); 17843fabe3fSedward (void) signal(SIGQUIT, SIG_IGN); 17913082428Sbill } 18013082428Sbill if (wanttty > 0) 18143fabe3fSedward (void) ioctl(FSHTTY, TIOCSPGRP, 18243fabe3fSedward (char *)&pgrp); 18313082428Sbill if (wanttty >= 0 && tpgrp >= 0) 18443fabe3fSedward (void) setpgrp(0, pgrp); 18513082428Sbill if (tpgrp > 0) 18613082428Sbill tpgrp = 0; 18713082428Sbill if (t->t_dflg & FNOHUP) 18843fabe3fSedward (void) signal(SIGHUP, SIG_IGN); 18913082428Sbill if (t->t_dflg & FNICE) 19043fabe3fSedward (void) setpriority(PRIO_PROCESS, 19143fabe3fSedward 0, t->t_nice); 19213082428Sbill } 19313082428Sbill 19413082428Sbill } 19513082428Sbill #endif 19613082428Sbill if (pid != 0) { 19713082428Sbill /* 19813082428Sbill * It would be better if we could wait for the 19913082428Sbill * whole job when we knew the last process 20013082428Sbill * had been started. Pwait, in fact, does 20113082428Sbill * wait for the whole job anyway, but this test 20213082428Sbill * doesn't really express our intentions. 20313082428Sbill */ 20443fabe3fSedward if (didfds==0 && t->t_dflg&FPIN) { 20543fabe3fSedward (void) close(pipein[0]); 20643fabe3fSedward (void) close(pipein[1]); 20743fabe3fSedward } 20813082428Sbill if ((t->t_dflg & (FPOU|FAND)) == 0) 20913082428Sbill pwait(); 21013082428Sbill break; 21113082428Sbill } 21213082428Sbill doio(t, pipein, pipeout); 21343fabe3fSedward if (t->t_dflg & FPOU) { 21443fabe3fSedward (void) close(pipeout[0]); 21543fabe3fSedward (void) close(pipeout[1]); 21643fabe3fSedward } 21713082428Sbill 21813082428Sbill /* 21913082428Sbill * Perform a builtin function. 22013082428Sbill * If we are not forked, arrange for possible stopping 22113082428Sbill */ 22213082428Sbill if (bifunc) { 22313082428Sbill func(t, bifunc); 22413082428Sbill if (forked) 22513082428Sbill exitstat(); 22613082428Sbill break; 22713082428Sbill } 22813082428Sbill if (t->t_dtyp != TPAR) { 22913082428Sbill doexec(t); 23013082428Sbill /*NOTREACHED*/ 23113082428Sbill } 23213082428Sbill /* 23313082428Sbill * For () commands must put new 0,1,2 in FSH* and recurse 23413082428Sbill */ 23513082428Sbill OLDSTD = dcopy(0, FOLDSTD); 23613082428Sbill SHOUT = dcopy(1, FSHOUT); 23713082428Sbill SHDIAG = dcopy(2, FSHDIAG); 23843fabe3fSedward (void) close(SHIN); 23943fabe3fSedward SHIN = -1; 24043fabe3fSedward didfds = 0; 24113082428Sbill wanttty = -1; 24213082428Sbill t->t_dspr->t_dflg |= t->t_dflg & FINT; 24313082428Sbill execute(t->t_dspr, wanttty); 24413082428Sbill exitstat(); 24513082428Sbill 24613082428Sbill case TFIL: 24713082428Sbill t->t_dcar->t_dflg |= FPOU | 24813082428Sbill (t->t_dflg & (FPIN|FAND|FDIAG|FINT)); 24913082428Sbill execute(t->t_dcar, wanttty, pipein, pv); 25013082428Sbill t->t_dcdr->t_dflg |= FPIN | 25113082428Sbill (t->t_dflg & (FPOU|FAND|FPAR|FINT)); 25213082428Sbill if (wanttty > 0) 25313082428Sbill wanttty = 0; /* got tty already */ 25413082428Sbill execute(t->t_dcdr, wanttty, pv, pipeout); 25513082428Sbill break; 25613082428Sbill 25713082428Sbill case TLST: 25813082428Sbill if (t->t_dcar) { 25913082428Sbill t->t_dcar->t_dflg |= t->t_dflg & FINT; 26013082428Sbill execute(t->t_dcar, wanttty); 26113082428Sbill /* 26213082428Sbill * In strange case of A&B make a new job after A 26313082428Sbill */ 26413082428Sbill if (t->t_dcar->t_dflg&FAND && t->t_dcdr && 26513082428Sbill (t->t_dcdr->t_dflg&FAND) == 0) 26613082428Sbill pendjob(); 26713082428Sbill } 26813082428Sbill if (t->t_dcdr) { 26913082428Sbill t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 27013082428Sbill execute(t->t_dcdr, wanttty); 27113082428Sbill } 27213082428Sbill break; 27313082428Sbill 27413082428Sbill case TOR: 27513082428Sbill case TAND: 27613082428Sbill if (t->t_dcar) { 27713082428Sbill t->t_dcar->t_dflg |= t->t_dflg & FINT; 27813082428Sbill execute(t->t_dcar, wanttty); 27913082428Sbill if ((getn(value("status")) == 0) != (t->t_dtyp == TAND)) 28013082428Sbill return; 28113082428Sbill } 28213082428Sbill if (t->t_dcdr) { 28313082428Sbill t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 28413082428Sbill execute(t->t_dcdr, wanttty); 28513082428Sbill } 28613082428Sbill break; 28713082428Sbill } 28813082428Sbill /* 28913082428Sbill * Fall through for all breaks from switch 29013082428Sbill * 29113082428Sbill * If there will be no more executions of this 29213082428Sbill * command, flush all file descriptors. 29313082428Sbill * Places that turn on the FREDO bit are responsible 29413082428Sbill * for doing donefds after the last re-execution 29513082428Sbill */ 29613082428Sbill if (didfds && !(t->t_dflg & FREDO)) 29713082428Sbill donefds(); 29813082428Sbill } 29913082428Sbill 30013082428Sbill #ifdef VFORK 30113082428Sbill vffree() 30213082428Sbill { 30313082428Sbill register char **v; 30413082428Sbill 30513082428Sbill if (v = gargv) 30643fabe3fSedward gargv = 0, xfree((char *)v); 30713082428Sbill if (v = pargv) 30843fabe3fSedward pargv = 0, xfree((char *)v); 30913082428Sbill _exit(1); 31013082428Sbill } 31113082428Sbill #endif 31213082428Sbill 31313082428Sbill /* 31413082428Sbill * Perform io redirection. 31513082428Sbill * We may or maynot be forked here. 31613082428Sbill */ 31713082428Sbill doio(t, pipein, pipeout) 31813082428Sbill register struct command *t; 31913082428Sbill int *pipein, *pipeout; 32013082428Sbill { 32113082428Sbill register char *cp; 32213082428Sbill register int flags = t->t_dflg; 32313082428Sbill 32413082428Sbill if (didfds || (flags & FREDO)) 32513082428Sbill return; 32613082428Sbill if ((flags & FHERE) == 0) { /* FHERE already done */ 32743fabe3fSedward (void) close(0); 32813082428Sbill if (cp = t->t_dlef) { 32913082428Sbill cp = globone(Dfix1(cp)); 33013082428Sbill xfree(cp); 33113082428Sbill if (open(cp, 0) < 0) 33213082428Sbill Perror(cp); 33343fabe3fSedward } else if (flags & FPIN) { 33443fabe3fSedward (void) dup(pipein[0]); 33543fabe3fSedward (void) close(pipein[0]); 33643fabe3fSedward (void) close(pipein[1]); 33743fabe3fSedward } else if ((flags & FINT) && tpgrp == -1) { 33843fabe3fSedward (void) close(0); 33943fabe3fSedward (void) open("/dev/null", 0); 34043fabe3fSedward } else 341cde959b4Sedward (void) dup(OLDSTD); 34213082428Sbill } 34343fabe3fSedward (void) close(1); 34413082428Sbill if (cp = t->t_drit) { 34513082428Sbill cp = globone(Dfix1(cp)); 34613082428Sbill xfree(cp); 34713082428Sbill if ((flags & FCAT) && open(cp, 1) >= 0) 34843fabe3fSedward (void) lseek(1, (off_t)0, 2); 34913082428Sbill else { 35013082428Sbill if (!(flags & FANY) && adrof("noclobber")) { 35113082428Sbill if (flags & FCAT) 35213082428Sbill Perror(cp); 35313082428Sbill chkclob(cp); 35413082428Sbill } 35513082428Sbill if (creat(cp, 0666) < 0) 35613082428Sbill Perror(cp); 35713082428Sbill } 35813082428Sbill } else if (flags & FPOU) 35943fabe3fSedward (void) dup(pipeout[1]); 36013082428Sbill else 361cde959b4Sedward (void) dup(SHOUT); 36213082428Sbill 36343fabe3fSedward (void) close(2); 36443fabe3fSedward if (flags & FDIAG) 36543fabe3fSedward (void) dup(1); 36643fabe3fSedward else 367cde959b4Sedward (void) dup(SHDIAG); 36813082428Sbill didfds = 1; 36913082428Sbill } 37013082428Sbill 37113082428Sbill mypipe(pv) 37213082428Sbill register int *pv; 37313082428Sbill { 37413082428Sbill 37513082428Sbill if (pipe(pv) < 0) 37613082428Sbill goto oops; 37713082428Sbill pv[0] = dmove(pv[0], -1); 37813082428Sbill pv[1] = dmove(pv[1], -1); 37913082428Sbill if (pv[0] >= 0 && pv[1] >= 0) 38013082428Sbill return; 38113082428Sbill oops: 38213082428Sbill error("Can't make pipe"); 38313082428Sbill } 38413082428Sbill 38513082428Sbill chkclob(cp) 38613082428Sbill register char *cp; 38713082428Sbill { 38813082428Sbill struct stat stb; 38913082428Sbill 39013082428Sbill if (stat(cp, &stb) < 0) 39113082428Sbill return; 39213082428Sbill if ((stb.st_mode & S_IFMT) == S_IFCHR) 39313082428Sbill return; 39413082428Sbill error("%s: File exists", cp); 39513082428Sbill } 396