1c1549ed3Sdist /* 2c1549ed3Sdist * Copyright (c) 1980 Regents of the University of California. 367f82af8Sedward * All rights reserved. The Berkeley Software License Agreement 4c1549ed3Sdist * specifies the terms and conditions for redistribution. 5c1549ed3Sdist */ 6c1549ed3Sdist 743fabe3fSedward #ifndef lint 8*5e5c7fccSmarc static char *sccsid = "@(#)sem.c 5.6 (Berkeley) 11/20/89"; 967f82af8Sedward #endif 1013082428Sbill 1113082428Sbill #include "sh.h" 1213082428Sbill #include "sh.proc.h" 1313082428Sbill #include <sys/ioctl.h> 14*5e5c7fccSmarc #include "pathnames.h" 1513082428Sbill 1613082428Sbill /* 1713082428Sbill * C shell 1813082428Sbill */ 1913082428Sbill 20*5e5c7fccSmarc static int nosigchld = 0, osigmask; 21*5e5c7fccSmarc static int onosigchld = 0, oosigmask; 2213082428Sbill /*VARARGS 1*/ 2313082428Sbill execute(t, wanttty, pipein, pipeout) 2413082428Sbill register struct command *t; 2513082428Sbill int wanttty, *pipein, *pipeout; 2613082428Sbill { 2713082428Sbill bool forked = 0; 2813082428Sbill struct biltins *bifunc; 2913082428Sbill int pid = 0; 3013082428Sbill int pv[2]; 3113082428Sbill 3213082428Sbill if (t == 0) 3313082428Sbill return; 34*5e5c7fccSmarc #ifdef REMOVE_THIS 35*5e5c7fccSmarc { short x=t->t_dtyp; 36*5e5c7fccSmarc int flg = t->t_dflg; 37*5e5c7fccSmarc printf("execute: cmd=%s pid=%d t_dtyp=%s wanttty=%d ", t->t_dcom[0], getpid(), 38*5e5c7fccSmarc x == TCOM ? "TCOM" : x == TPAR ? "TPAR" : x == TFIL ? "TFIL" : 39*5e5c7fccSmarc x == TLST ? "TLST" : x == TOR ? "TOR" : x == TAND ? "TAND" : "UNKNOWN", 40*5e5c7fccSmarc wanttty); 41*5e5c7fccSmarc if (flg&FAND) printf("FAND "); if (flg&FCAT) printf("FCAT "); 42*5e5c7fccSmarc if (flg&FPIN) printf("FPIN "); if (flg&FPOU) printf("FPOU "); 43*5e5c7fccSmarc if (flg&FPAR) printf("FPAR "); if (flg&FINT) printf("FINT "); 44*5e5c7fccSmarc if (flg&FDIAG) printf("FDIAG "); if (flg&FANY) printf("FANY "); 45*5e5c7fccSmarc if (flg&FHERE) printf("FHERE "); if (flg&FREDO) printf("FREDO "); 46*5e5c7fccSmarc if (flg&FNICE) printf("FNICE "); if (flg&FNOHUP) printf("FNOHUP "); 47*5e5c7fccSmarc if (flg&FTIME) printf("FTIME "); printf("\n"); 48*5e5c7fccSmarc } 49*5e5c7fccSmarc #endif 5013082428Sbill if ((t->t_dflg & FAND) && wanttty > 0) 5113082428Sbill wanttty = 0; 5213082428Sbill switch (t->t_dtyp) { 5313082428Sbill 5413082428Sbill case TCOM: 5513082428Sbill if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE) 5643fabe3fSedward (void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1); 5713082428Sbill if ((t->t_dflg & FREDO) == 0) 5813082428Sbill Dfix(t); /* $ " ' \ */ 5913082428Sbill if (t->t_dcom[0] == 0) 6013082428Sbill return; 6113082428Sbill /* fall into... */ 6213082428Sbill 6313082428Sbill case TPAR: 6413082428Sbill if (t->t_dflg & FPOU) 6513082428Sbill mypipe(pipeout); 6613082428Sbill /* 6713082428Sbill * Must do << early so parent will know 6813082428Sbill * where input pointer should be. 6913082428Sbill * If noexec then this is all we do. 7013082428Sbill */ 7113082428Sbill if (t->t_dflg & FHERE) { 7243fabe3fSedward (void) close(0); 7313082428Sbill heredoc(t->t_dlef); 7413082428Sbill if (noexec) 7543fabe3fSedward (void) close(0); 7613082428Sbill } 7713082428Sbill if (noexec) 7813082428Sbill break; 7913082428Sbill 8013082428Sbill set("status", "0"); 8113082428Sbill 8213082428Sbill /* 8313082428Sbill * This mess is the necessary kludge to handle the prefix 8413082428Sbill * builtins: nice, nohup, time. These commands can also 8513082428Sbill * be used by themselves, and this is not handled here. 8613082428Sbill * This will also work when loops are parsed. 8713082428Sbill */ 8813082428Sbill while (t->t_dtyp == TCOM) 8913082428Sbill if (eq(t->t_dcom[0], "nice")) 9013082428Sbill if (t->t_dcom[1]) 9113082428Sbill if (any(t->t_dcom[1][0], "+-")) 9213082428Sbill if (t->t_dcom[2]) { 9313082428Sbill setname("nice"); 9413082428Sbill t->t_nice = getn(t->t_dcom[1]); 9513082428Sbill lshift(t->t_dcom, 2); 9613082428Sbill t->t_dflg |= FNICE; 9713082428Sbill } else 9813082428Sbill break; 9913082428Sbill else { 10013082428Sbill t->t_nice = 4; 10113082428Sbill lshift(t->t_dcom, 1); 10213082428Sbill t->t_dflg |= FNICE; 10313082428Sbill } 10413082428Sbill else 10513082428Sbill break; 10613082428Sbill else if (eq(t->t_dcom[0], "nohup")) 10713082428Sbill if (t->t_dcom[1]) { 10813082428Sbill t->t_dflg |= FNOHUP; 10913082428Sbill lshift(t->t_dcom, 1); 11013082428Sbill } else 11113082428Sbill break; 11213082428Sbill else if (eq(t->t_dcom[0], "time")) 11313082428Sbill if (t->t_dcom[1]) { 11413082428Sbill t->t_dflg |= FTIME; 11513082428Sbill lshift(t->t_dcom, 1); 11613082428Sbill } else 11713082428Sbill break; 11813082428Sbill else 11913082428Sbill break; 12013082428Sbill /* 12113082428Sbill * Check if we have a builtin function and remember which one. 12213082428Sbill */ 12313082428Sbill bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0; 12413082428Sbill 12513082428Sbill /* 12613082428Sbill * We fork only if we are timed, or are not the end of 12713082428Sbill * a parenthesized list and not a simple builtin function. 12813082428Sbill * Simple meaning one that is not pipedout, niced, nohupped, 12913082428Sbill * or &'d. 13013082428Sbill * It would be nice(?) to not fork in some of these cases. 13113082428Sbill */ 13213082428Sbill if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 && 13313082428Sbill (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP)))) 13413082428Sbill #ifdef VFORK 13513082428Sbill if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc) 13613082428Sbill #endif 137*5e5c7fccSmarc { forked++; 138*5e5c7fccSmarc if (wanttty >= 0 && !nosigchld) { 139*5e5c7fccSmarc #ifdef REMOVE_THIS 140*5e5c7fccSmarc printf("(%d) blocking sigchld\n", getpid()); 141*5e5c7fccSmarc #endif 142*5e5c7fccSmarc osigmask = sigblock(sigmask(SIGCHLD)); 143*5e5c7fccSmarc nosigchld = 1; 144*5e5c7fccSmarc } 145*5e5c7fccSmarc 146*5e5c7fccSmarc pid = pfork(t, wanttty); 147*5e5c7fccSmarc if (pid == 0 && nosigchld) { 148*5e5c7fccSmarc #ifdef REMOVE_THIS 149*5e5c7fccSmarc printf("%d unblocking sigchld after fork\n", getpid()); 150*5e5c7fccSmarc #endif 151*5e5c7fccSmarc sigsetmask(osigmask); 152*5e5c7fccSmarc nosigchld = 0; 153*5e5c7fccSmarc } 154*5e5c7fccSmarc } 15513082428Sbill #ifdef VFORK 15613082428Sbill else { 157*5e5c7fccSmarc sig_t vffree; 15843fabe3fSedward int ochild, osetintr, ohaderr, odidfds; 15913082428Sbill int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; 1603bb023eaSbostic long omask; 16113082428Sbill 16215d9e91aSlepreau /* 16315d9e91aSlepreau * Prepare for the vfork by saving everything 16415d9e91aSlepreau * that the child corrupts before it exec's. 16515d9e91aSlepreau * Note that in some signal implementations 16615d9e91aSlepreau * which keep the signal info in user space 16715d9e91aSlepreau * (e.g. Sun's) it will also be necessary to 16815d9e91aSlepreau * save and restore the current sigvec's for 16915d9e91aSlepreau * the signals the child touches before it 17015d9e91aSlepreau * exec's. 17115d9e91aSlepreau */ 172*5e5c7fccSmarc if (wanttty >= 0 && !nosigchld && !noexec) { 173*5e5c7fccSmarc #ifdef REMOVE_THIS 174*5e5c7fccSmarc printf("(%d) blocking sigchld\n", getpid()); 175*5e5c7fccSmarc #endif 176*5e5c7fccSmarc osigmask = sigblock(sigmask(SIGCHLD)); 177*5e5c7fccSmarc nosigchld = 1; 178*5e5c7fccSmarc } 1791e9806efSralph omask = sigblock(sigmask(SIGCHLD)); 18013082428Sbill ochild = child; osetintr = setintr; 18143fabe3fSedward ohaderr = haderr; odidfds = didfds; 18213082428Sbill oSHIN = SHIN; oSHOUT = SHOUT; 18313082428Sbill oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; 184*5e5c7fccSmarc oosigmask = osigmask; onosigchld = nosigchld; 18513082428Sbill Vsav = Vdp = 0; Vav = 0; 18613082428Sbill pid = vfork(); 18713082428Sbill if (pid < 0) { 18843fabe3fSedward (void) sigsetmask(omask); 18913082428Sbill error("No more processes"); 19013082428Sbill } 19113082428Sbill forked++; 19215d9e91aSlepreau if (pid) { /* parent */ 19313082428Sbill child = ochild; setintr = osetintr; 19413082428Sbill haderr = ohaderr; didfds = odidfds; 19543fabe3fSedward SHIN = oSHIN; 19613082428Sbill SHOUT = oSHOUT; SHDIAG = oSHDIAG; 19713082428Sbill OLDSTD = oOLDSTD; tpgrp = otpgrp; 198*5e5c7fccSmarc osigmask = oosigmask; nosigchld = onosigchld; 19913082428Sbill xfree(Vsav); Vsav = 0; 20013082428Sbill xfree(Vdp); Vdp = 0; 20143fabe3fSedward xfree((char *)Vav); Vav = 0; 20213082428Sbill /* this is from pfork() */ 20313082428Sbill palloc(pid, t); 20443fabe3fSedward (void) sigsetmask(omask); 20515d9e91aSlepreau } else { /* child */ 20613082428Sbill /* this is from pfork() */ 20713082428Sbill int pgrp; 20813082428Sbill bool ignint = 0; 20913082428Sbill 210*5e5c7fccSmarc if (nosigchld) { 211*5e5c7fccSmarc #ifdef REMOVE_THIS 212*5e5c7fccSmarc printf("%d unblocking sigchld after fork\n", getpid()); 213*5e5c7fccSmarc #endif 214*5e5c7fccSmarc sigsetmask(osigmask); 215*5e5c7fccSmarc nosigchld = 0; 216*5e5c7fccSmarc } 21713082428Sbill if (setintr) 21813082428Sbill ignint = 21913082428Sbill (tpgrp == -1 && (t->t_dflg&FINT)) 22013082428Sbill || gointr && eq(gointr, "-"); 22113082428Sbill pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 22213082428Sbill child++; 22313082428Sbill if (setintr) { 22413082428Sbill setintr = 0; 2252c8ae23aSsam #ifdef notdef 22643fabe3fSedward (void) signal(SIGCHLD, SIG_DFL); 2272c8ae23aSsam #endif 22843fabe3fSedward (void) signal(SIGINT, ignint ? 2291e9806efSralph SIG_IGN : vffree); 23043fabe3fSedward (void) signal(SIGQUIT, ignint ? 2311e9806efSralph SIG_IGN : SIG_DFL); 23213082428Sbill if (wanttty >= 0) { 23343fabe3fSedward (void) signal(SIGTSTP, SIG_DFL); 23443fabe3fSedward (void) signal(SIGTTIN, SIG_DFL); 23543fabe3fSedward (void) signal(SIGTTOU, SIG_DFL); 23613082428Sbill } 23743fabe3fSedward (void) signal(SIGTERM, parterm); 23813082428Sbill } else if (tpgrp == -1 && (t->t_dflg&FINT)) { 23943fabe3fSedward (void) signal(SIGINT, SIG_IGN); 24043fabe3fSedward (void) signal(SIGQUIT, SIG_IGN); 24113082428Sbill } 242*5e5c7fccSmarc if (wanttty >= 0 && tpgrp >= 0) 243*5e5c7fccSmarc (void) setpgrp(0, pgrp); 24413082428Sbill if (wanttty > 0) 24543fabe3fSedward (void) ioctl(FSHTTY, TIOCSPGRP, 24643fabe3fSedward (char *)&pgrp); 24713082428Sbill if (tpgrp > 0) 24813082428Sbill tpgrp = 0; 24913082428Sbill if (t->t_dflg & FNOHUP) 25043fabe3fSedward (void) signal(SIGHUP, SIG_IGN); 25113082428Sbill if (t->t_dflg & FNICE) 25215d9e91aSlepreau (void) setpriority(PRIO_PROCESS, 25315d9e91aSlepreau 0, t->t_nice); 25413082428Sbill } 25513082428Sbill 25613082428Sbill } 25713082428Sbill #endif 25813082428Sbill if (pid != 0) { 25913082428Sbill /* 26013082428Sbill * It would be better if we could wait for the 26113082428Sbill * whole job when we knew the last process 26213082428Sbill * had been started. Pwait, in fact, does 26313082428Sbill * wait for the whole job anyway, but this test 26413082428Sbill * doesn't really express our intentions. 26513082428Sbill */ 26643fabe3fSedward if (didfds==0 && t->t_dflg&FPIN) { 26743fabe3fSedward (void) close(pipein[0]); 26843fabe3fSedward (void) close(pipein[1]); 26943fabe3fSedward } 270*5e5c7fccSmarc if ((t->t_dflg & FPOU) == 0) { 271*5e5c7fccSmarc #ifdef REMOVE_THIS 272*5e5c7fccSmarc printf("(%d) last command - should unblock sigchld? (%d)\n", getpid(), nosigchld); 273*5e5c7fccSmarc #endif 274*5e5c7fccSmarc if (nosigchld) { 275*5e5c7fccSmarc #ifdef foobarbaz 276*5e5c7fccSmarc printf("DID\n"); 277*5e5c7fccSmarc #endif 278*5e5c7fccSmarc sigsetmask(osigmask); 279*5e5c7fccSmarc nosigchld = 0; 280*5e5c7fccSmarc } 281*5e5c7fccSmarc if ((t->t_dflg & FAND) == 0) 28213082428Sbill pwait(); 283*5e5c7fccSmarc } 28413082428Sbill break; 28513082428Sbill } 28613082428Sbill doio(t, pipein, pipeout); 28743fabe3fSedward if (t->t_dflg & FPOU) { 28843fabe3fSedward (void) close(pipeout[0]); 28943fabe3fSedward (void) close(pipeout[1]); 29043fabe3fSedward } 29113082428Sbill 29213082428Sbill /* 29313082428Sbill * Perform a builtin function. 29413082428Sbill * If we are not forked, arrange for possible stopping 29513082428Sbill */ 29613082428Sbill if (bifunc) { 29713082428Sbill func(t, bifunc); 29813082428Sbill if (forked) 29913082428Sbill exitstat(); 30013082428Sbill break; 30113082428Sbill } 30213082428Sbill if (t->t_dtyp != TPAR) { 30313082428Sbill doexec(t); 30413082428Sbill /*NOTREACHED*/ 30513082428Sbill } 30613082428Sbill /* 30713082428Sbill * For () commands must put new 0,1,2 in FSH* and recurse 30813082428Sbill */ 30913082428Sbill OLDSTD = dcopy(0, FOLDSTD); 31013082428Sbill SHOUT = dcopy(1, FSHOUT); 31113082428Sbill SHDIAG = dcopy(2, FSHDIAG); 31243fabe3fSedward (void) close(SHIN); 31343fabe3fSedward SHIN = -1; 31443fabe3fSedward didfds = 0; 31513082428Sbill wanttty = -1; 31613082428Sbill t->t_dspr->t_dflg |= t->t_dflg & FINT; 31713082428Sbill execute(t->t_dspr, wanttty); 31813082428Sbill exitstat(); 31913082428Sbill 32013082428Sbill case TFIL: 32113082428Sbill t->t_dcar->t_dflg |= FPOU | 32213082428Sbill (t->t_dflg & (FPIN|FAND|FDIAG|FINT)); 32313082428Sbill execute(t->t_dcar, wanttty, pipein, pv); 32413082428Sbill t->t_dcdr->t_dflg |= FPIN | 32513082428Sbill (t->t_dflg & (FPOU|FAND|FPAR|FINT)); 32613082428Sbill if (wanttty > 0) 32713082428Sbill wanttty = 0; /* got tty already */ 32813082428Sbill execute(t->t_dcdr, wanttty, pv, pipeout); 32913082428Sbill break; 33013082428Sbill 33113082428Sbill case TLST: 33213082428Sbill if (t->t_dcar) { 33313082428Sbill t->t_dcar->t_dflg |= t->t_dflg & FINT; 33413082428Sbill execute(t->t_dcar, wanttty); 33513082428Sbill /* 33613082428Sbill * In strange case of A&B make a new job after A 33713082428Sbill */ 33813082428Sbill if (t->t_dcar->t_dflg&FAND && t->t_dcdr && 33913082428Sbill (t->t_dcdr->t_dflg&FAND) == 0) 34013082428Sbill pendjob(); 34113082428Sbill } 34213082428Sbill if (t->t_dcdr) { 34313082428Sbill t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 34413082428Sbill execute(t->t_dcdr, wanttty); 34513082428Sbill } 34613082428Sbill break; 34713082428Sbill 34813082428Sbill case TOR: 34913082428Sbill case TAND: 35013082428Sbill if (t->t_dcar) { 35113082428Sbill t->t_dcar->t_dflg |= t->t_dflg & FINT; 35213082428Sbill execute(t->t_dcar, wanttty); 35313082428Sbill if ((getn(value("status")) == 0) != (t->t_dtyp == TAND)) 35413082428Sbill return; 35513082428Sbill } 35613082428Sbill if (t->t_dcdr) { 35713082428Sbill t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 35813082428Sbill execute(t->t_dcdr, wanttty); 35913082428Sbill } 36013082428Sbill break; 36113082428Sbill } 36213082428Sbill /* 36313082428Sbill * Fall through for all breaks from switch 36413082428Sbill * 36513082428Sbill * If there will be no more executions of this 36613082428Sbill * command, flush all file descriptors. 36713082428Sbill * Places that turn on the FREDO bit are responsible 36813082428Sbill * for doing donefds after the last re-execution 36913082428Sbill */ 37013082428Sbill if (didfds && !(t->t_dflg & FREDO)) 37113082428Sbill donefds(); 37213082428Sbill } 37313082428Sbill 37413082428Sbill #ifdef VFORK 37513082428Sbill vffree() 37613082428Sbill { 37713082428Sbill register char **v; 37813082428Sbill 37913082428Sbill if (v = gargv) 38043fabe3fSedward gargv = 0, xfree((char *)v); 38113082428Sbill if (v = pargv) 38243fabe3fSedward pargv = 0, xfree((char *)v); 38313082428Sbill _exit(1); 38413082428Sbill } 38513082428Sbill #endif 38613082428Sbill 38713082428Sbill /* 38813082428Sbill * Perform io redirection. 38913082428Sbill * We may or maynot be forked here. 39013082428Sbill */ 39113082428Sbill doio(t, pipein, pipeout) 39213082428Sbill register struct command *t; 39313082428Sbill int *pipein, *pipeout; 39413082428Sbill { 39513082428Sbill register char *cp; 39613082428Sbill register int flags = t->t_dflg; 39713082428Sbill 39813082428Sbill if (didfds || (flags & FREDO)) 39913082428Sbill return; 40013082428Sbill if ((flags & FHERE) == 0) { /* FHERE already done */ 40143fabe3fSedward (void) close(0); 40213082428Sbill if (cp = t->t_dlef) { 40313082428Sbill cp = globone(Dfix1(cp)); 40413082428Sbill xfree(cp); 40513082428Sbill if (open(cp, 0) < 0) 40613082428Sbill Perror(cp); 40743fabe3fSedward } else if (flags & FPIN) { 40843fabe3fSedward (void) dup(pipein[0]); 40943fabe3fSedward (void) close(pipein[0]); 41043fabe3fSedward (void) close(pipein[1]); 41143fabe3fSedward } else if ((flags & FINT) && tpgrp == -1) { 41243fabe3fSedward (void) close(0); 413*5e5c7fccSmarc (void) open(_PATH_DEVNULL, 0); 41443fabe3fSedward } else 415cde959b4Sedward (void) dup(OLDSTD); 41613082428Sbill } 41743fabe3fSedward (void) close(1); 41813082428Sbill if (cp = t->t_drit) { 41913082428Sbill cp = globone(Dfix1(cp)); 42013082428Sbill xfree(cp); 42113082428Sbill if ((flags & FCAT) && open(cp, 1) >= 0) 42243fabe3fSedward (void) lseek(1, (off_t)0, 2); 42313082428Sbill else { 42413082428Sbill if (!(flags & FANY) && adrof("noclobber")) { 42513082428Sbill if (flags & FCAT) 42613082428Sbill Perror(cp); 42713082428Sbill chkclob(cp); 42813082428Sbill } 42913082428Sbill if (creat(cp, 0666) < 0) 43013082428Sbill Perror(cp); 43113082428Sbill } 43213082428Sbill } else if (flags & FPOU) 43343fabe3fSedward (void) dup(pipeout[1]); 43413082428Sbill else 435cde959b4Sedward (void) dup(SHOUT); 43613082428Sbill 43743fabe3fSedward (void) close(2); 43843fabe3fSedward if (flags & FDIAG) 43943fabe3fSedward (void) dup(1); 44043fabe3fSedward else 441cde959b4Sedward (void) dup(SHDIAG); 44213082428Sbill didfds = 1; 44313082428Sbill } 44413082428Sbill 44513082428Sbill mypipe(pv) 44613082428Sbill register int *pv; 44713082428Sbill { 44813082428Sbill 44913082428Sbill if (pipe(pv) < 0) 45013082428Sbill goto oops; 45113082428Sbill pv[0] = dmove(pv[0], -1); 45213082428Sbill pv[1] = dmove(pv[1], -1); 45313082428Sbill if (pv[0] >= 0 && pv[1] >= 0) 45413082428Sbill return; 45513082428Sbill oops: 45613082428Sbill error("Can't make pipe"); 45713082428Sbill } 45813082428Sbill 45913082428Sbill chkclob(cp) 46013082428Sbill register char *cp; 46113082428Sbill { 46213082428Sbill struct stat stb; 46313082428Sbill 46413082428Sbill if (stat(cp, &stb) < 0) 46513082428Sbill return; 46613082428Sbill if ((stb.st_mode & S_IFMT) == S_IFCHR) 46713082428Sbill return; 46813082428Sbill error("%s: File exists", cp); 46913082428Sbill } 470