/* @(#)sh.sem.c 2.1 SCCS id keyword */ /* Copyright (c) 1980 Regents of the University of California */ #include "sh.h" /* * C shell */ execute(t, pipein, pipeout) register struct command *t; int *pipein, *pipeout; { int pid, flags, pv[2]; register struct command *t1; register char *cp; bool forked = 0; bool shudint, shudhup; #ifdef VFORK int (*savint)(), vffree(); int ochild, osetintr, ohaderr, otimflg, odidfds, odidcch; int oSHIN, oSHOUT, oSHDIAG, oOLDSTD; int isvfork = 0; #endif if (t == 0) return; switch (t->t_dtyp) { case TCOM: cp = t->t_dcom[0]; if ((cp[0] & (QUOTE|TRIM)) == QUOTE) strcpy(cp, cp + 1); if ((t->t_dflg & FREDO) == 0) Dfix(t); /* $ " ' \ */ if (t->t_dcom[0] == 0) return; /* fall into... */ case TPAR: flags = t->t_dflg; if (flags & FPOU) mypipe(pipeout); /* * A child will be interruptible only under very * certain conditions: * we must be monkeying with interrupts * the child must not be &'ed * we must not have had an "onintr -" */ shudint = setintr && (flags & FINT) == 0 && (!gointr || !eq(gointr, "-")); shudhup = (flags & FAND) == 0; /* * Must do << early so parent will know * where input pointer should be */ if (flags & FHERE) close(0), heredoc(t->t_dlef); /* * If not executing commands then * all we must do is read forward in the input to * account for << redirection if present. */ if (noexec) { if (flags & FHERE) close(0); return; } set("status", "0"); pid = 0; /* * Built-in functions */ if (t->t_dtyp == TCOM && isbfunc(t->t_dcom[0])) { /* * If output is piped, or running & and we would * eventually fork for non-builtin commands, * then do it now, so we won't block. */ if ((flags & (FPOU|FAND)) && (flags & FPAR) == 0) pid = dofork(shudint, shudhup), forked++; /* * If the builtin is actually executed (some, e.g. * time and nice may refuse to execute here) * then either exit (if we forked) or close i/o * and continue execution (if we didn't). */ if (pid == 0) { doio(t, pipein, pipeout); if (flags & FPOU) { close(pipeout[0]), close(pipeout[1]); pipeout[0] = pipeout[1] = -1; } if (setintr && forked) { if (shudint) signal(SIGINT, SIG_DFL), signal(SIGQUIT, SIG_DFL); signal(SIGTERM, parterm); if (flags & FINT) setintr = 0; } if (func(t, pipein, pipeout)) { if (forked) exitstat(); if (didfds && !(t->t_dflg & FREDO)) donefds(); return; } } } /* * Now, we must make a new process since either the * command is non-builtin, a parenthesized list, * or builtin such as time or nice which really * requires a child. */ if (!forked && (flags & FPAR) == 0) #ifdef VFORK if (t->t_dtyp == TPAR || (flags&FREDO) || eq(t->t_dcom[0], "nice") || eq(t->t_dcom[0], "nohup")) #endif pid = dofork(shudint, shudhup); #ifdef VFORK else { savint = signal(SIGINT, SIG_IGN); ochild = child; osetintr = setintr; ohaderr = haderr; otimflg = timflg; odidfds = didfds; odidcch = didcch; oSHIN = SHIN; oSHOUT = SHOUT; oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; Vsav = Vdp = 0; Vav = 0; isvfork++; pid = vfork(); if (pid < 0) { signal(SIGINT, savint); error("No more processes"); } if (pid == 0) { child++; signal(SIGINT, shudint ? SIG_DFL : savint); if (!shudhup) signal(SIGHUP, SIG_IGN); } else { child = ochild; setintr = osetintr; haderr = ohaderr; timflg = otimflg; didfds = odidfds; didcch = odidcch; SHIN = oSHIN; SHOUT = oSHOUT; SHDIAG = oSHDIAG; OLDSTD = oOLDSTD; xfree(Vsav), Vsav = 0; xfree(Vdp), Vdp = 0; xfree(Vav), Vav = 0; signal(SIGINT, savint); } } #endif if (pid != 0) { /* * The parent path (or nobody does this if * (flags & FPAR), i.e. date in (set;date)) */ if (didfds == 0 && (flags & FPIN)) close(pipein[0]), close(pipein[1]); if (didfds && !(t->t_dflg & FREDO)) donefds(); if (flags & FPRS) printf("%d\n", pid), set("child", putn(pid)); /* * Unless output is piped or command is & * wait for it. */ if (t->t_dtyp == TCOM) cadd(pid, t->t_dcom[0]); else cadd(pid, "()"); if ((flags & (FPOU|FAND)) == 0) pwait(pid); return; } /* * Insure that this (child) shell doesn't muck on */ child++; /* * If havent yet, finally set up the file descriptors. */ doio(t, pipein, pipeout); if (flags & FPOU) close(pipeout[0]), close(pipeout[1]); /* * If mucking with interrupts fix interrupt, quit, * and terminate handling ... in any case set setintr * to 0 if we are not interruptible so that no further * interrupt mucking occurs. */ if (setintr) { if (shudint) { signal(SIGQUIT, SIG_DFL); #ifdef VFORK if (isvfork) signal(SIGINT, vffree); else #endif signal(SIGINT, SIG_DFL); } signal(SIGTERM, parterm); if (flags & FINT) setintr = 0; } /* * For () commands must put new 0,1,2 in FSH* and recurse */ if (t->t_dtyp == TPAR) { t1 = t->t_dspr; t1->t_dflg |= flags & FINT; OLDSTD = dcopy(0, FOLDSTD); SHOUT = dcopy(1, FSHOUT); SHDIAG = dcopy(2, FSHDIAG); close(SHIN), SHIN = -1; didcch = 0, didfds = 0; execute(t1); exitstat(); } if (eq(t->t_dcom[0], "nice")) { /* sigh... nice(20); nice(-10); */ cp = t->t_dcom[1]; if (any(cp[0], "+-")) nice(getn(cp)), lshift(t->t_dcom, 2); else nice(4), lshift(t->t_dcom, 1); t->t_dflg = FPAR | FREDO; execute(t); exitstat(); } if (eq(t->t_dcom[0], "nohup")) { if (setintr == 0) signal(SIGHUP, SIG_IGN); signal(SIGTERM, SIG_IGN); lshift(t->t_dcom, 1); t->t_dflg = FPAR | FREDO; execute(t); exitstat(); } doexec(t); /* no return */ case TFIL: flags = t->t_dflg; t1 = t->t_dcar; t1->t_dflg |= FPOU | (flags & (FPIN|FINT|FPRS|FDIAG)); execute(t1, pipein, pv); t1 = t->t_dcdr; t1->t_dflg |= FPIN | (flags & (FPOU|FINT|FAND|FPRS|FPAR)); execute(t1, pv, pipeout); return; case TLST: flags = t->t_dflg & FINT; if (t1 = t->t_dcar) t1->t_dflg |= flags, execute(t1); if (t1 = t->t_dcdr) t1->t_dflg |= t->t_dflg & (FINT|FPAR), execute(t1); return; case TOR: case TAND: flags = t->t_dflg & FINT; if (t1 = t->t_dcar) { t1->t_dflg |= flags, execute(t1); if ((getn(value("status")) == 0) != (t->t_dtyp == TAND)) return; } if (t1 = t->t_dcdr) t1->t_dflg |= t->t_dflg & (FINT|FPAR), execute(t1); return; } } #ifdef VFORK vffree() { register char **v; if (v = gargv) gargv = 0, xfree(gargv); if (v = pargv) pargv = 0, xfree(pargv); _exit(1); } #endif doio(t, pipein, pipeout) register struct command *t; int *pipein, *pipeout; { register char *cp; register int flags = t->t_dflg; char *dp; if (didfds || (flags & FREDO)) return; if (flags & FHERE) goto skipin; close(0); if (cp = t->t_dlef) { cp = globone(dp = Dfix1(cp)); xfree(dp); xfree(cp); if (open(cp, 0) < 0) Perror(cp); } else if (flags & FPIN) dup(pipein[0]), close(pipein[0]), close(pipein[1]); else if (flags & FINT) close(0), open("/dev/null", 0); else dup(OLDSTD); skipin: close(1); if (cp = t->t_drit) { cp = globone(dp = Dfix1(cp)); xfree(dp); xfree(cp); if ((flags & FCAT) && open(cp, 1) >= 0) lseek(1, 0l, 2); else { if (!(flags & FANY) && adrof("noclobber")) { if (flags & FCAT) Perror(cp); chkclob(cp); } #ifdef V6 if (creat(cp, 0644) < 0) Perror(cp); #else if (creat(cp, 0666) < 0) Perror(cp); #endif } } else dup((flags & FPOU) ? pipeout[1] : SHOUT); close(2); dup((flags & FDIAG) ? 1 : SHDIAG); didfds = 1; } dofork(shudint, shudhup) bool shudint, shudhup; { register int pid, (*savint)(); savint = signal(SIGINT, SIG_IGN); pid = fork(); if (pid < 0) { signal(SIGINT, savint); error("No more processes"); } if (pid == 0) { child++; signal(SIGINT, shudint ? SIG_DFL : savint); if (!shudhup) signal(SIGHUP, SIG_IGN); } else signal(SIGINT, savint); return (pid); } mypipe(pv) register int *pv; { if (pipe(pv) < 0) goto oops; pv[0] = dmove(pv[0], -1); pv[1] = dmove(pv[1], -1); if (pv[0] >= 0 && pv[1] >= 0) return; oops: error("Can't make pipe"); } chkclob(cp) register char *cp; { struct stat stb; if (stat(cp, &stb) < 0) return; if ((stb.st_mode & S_IFMT) == S_IFCHR) return; error("%s: File exists", cp); }