BSD 4 release
[unix-history] / usr / src / cmd / csh / sh.sem.c
index 5912144..f29027a 100644 (file)
-/* Copyright (c) 1979 Regents of the University of California */
+static char *sccsid = "@(#)sh.sem.c 4.1 10/9/80";
+
 #include "sh.h"
 #include "sh.h"
+#include "sh.proc.h"
+#include <sys/ioctl.h>
 
 /*
  * C shell
  */
 
 
 /*
  * C shell
  */
 
-execute(t, pipein, pipeout)
+/*VARARGS 1*/
+execute(t, wanttty, pipein, pipeout)
        register struct command *t;
        register struct command *t;
-       int *pipein, *pipeout;
+       int wanttty, *pipein, *pipeout;
 {
 {
-       int pid, flags, pv[2];
-       register struct command *t1;
-       register char *cp;
        bool forked = 0;
        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
+       struct biltins *bifunc;
+       int pid = 0;
+       int pv[2];
 
        if (t == 0)
                return;
 
        if (t == 0)
                return;
+       if ((t->t_dflg & FAND) && wanttty > 0)
+               wanttty = 0;
        switch (t->t_dtyp) {
 
        case TCOM:
        switch (t->t_dtyp) {
 
        case TCOM:
-               cp = t->t_dcom[0];
-               if ((cp[0] & (QUOTE|TRIM)) == QUOTE)
-                       strcpy(cp, cp + 1);
+               if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE)
+                       strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
                if ((t->t_dflg & FREDO) == 0)
                        Dfix(t);                /* $ " ' \ */
                if ((t->t_dflg & FREDO) == 0)
                        Dfix(t);                /* $ " ' \ */
+               if (t->t_dcom[0] == 0)
+                       return;
                /* fall into... */
 
        case TPAR:
                /* fall into... */
 
        case TPAR:
-               flags = t->t_dflg;
-               if (flags & FPOU)
+               if (t->t_dflg & FPOU)
                        mypipe(pipeout);
                        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
                /*
                 * Must do << early so parent will know
-                * where input pointer should be
+                * where input pointer should be.
+                * If noexec then this is all we do.
                 */
                 */
-               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)
+               if (t->t_dflg & FHERE) {
+                       close(0);
+                       heredoc(t->t_dlef);
+                       if (noexec)
                                close(0);
                                close(0);
-                       return;
                }
                }
+               if (noexec)
+                       break;
 
                set("status", "0");
 
                set("status", "0");
-               pid = 0;
 
                /*
 
                /*
-                * Built-in functions
+                * This mess is the necessary kludge to handle the prefix
+                * builtins: nice, nohup, time.  These commands can also
+                * be used by themselves, and this is not handled here.
+                * This will also work when loops are parsed.
                 */
                 */
-               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;
-                               }
-                       }
-               }
+               while (t->t_dtyp == TCOM)
+                       if (eq(t->t_dcom[0], "nice"))
+                               if (t->t_dcom[1])
+                                       if (any(t->t_dcom[1][0], "+-"))
+                                               if (t->t_dcom[2]) {
+                                                       setname("nice");
+                                                       t->t_nice = getn(t->t_dcom[1]);
+                                                       lshift(t->t_dcom, 2);
+                                                       t->t_dflg |= FNICE;
+                                               } else
+                                                       break;
+                                       else {
+                                               t->t_nice = 4;
+                                               lshift(t->t_dcom, 1);
+                                               t->t_dflg |= FNICE;
+                                       }
+                               else
+                                       break;
+                       else if (eq(t->t_dcom[0], "nohup"))
+                               if (t->t_dcom[1]) {
+                                       t->t_dflg |= FNOHUP;
+                                       lshift(t->t_dcom, 1);
+                               } else
+                                       break;
+                       else if (eq(t->t_dcom[0], "time"))
+                               if (t->t_dcom[1]) {
+                                       t->t_dflg |= FTIME;
+                                       lshift(t->t_dcom, 1);
+                               } else
+                                       break;
+                       else
+                               break;
+               /*
+                * Check if we have a builtin function and remember which one.
+                */
+               bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0;
 
                /*
 
                /*
-                * 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.
+                * We fork only if we are timed, or are not the end of
+                * a parenthesized list and not a simple builtin function.
+                * Simple meaning one that is not pipedout, niced, nohupped,
+                * or &'d.
+                * It would be nice(?) to not fork in some of these cases.
                 */
                 */
-               if (!forked && (flags & FPAR) == 0)
+               if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 &&
+                    (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP))))
 #ifdef VFORK
 #ifdef VFORK
-                       if (t->t_dtyp == TPAR || (flags&FREDO) ||
-                           eq(t->t_dcom[0], "nice") || eq(t->t_dcom[0], "nohup"))
+                   if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc)
 #endif
 #endif
-                               pid = dofork(shudint, shudhup);
+                       { forked++; pid = pfork(t, wanttty); }
 #ifdef VFORK
 #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);
+                   else {
+                       int vffree();
+                       int ochild, osetintr, ohaderr, odidfds, odidcch;
+                       int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp;
+
+                       sighold(SIGCHLD);
+                       ochild = child; osetintr = setintr;
+                       ohaderr = haderr; odidfds = didfds; odidcch = didcch;
+                       oSHIN = SHIN; oSHOUT = SHOUT;
+                       oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp;
+                       Vsav = Vdp = 0; Vav = 0;
+                       pid = vfork();
+                       if (pid < 0) {
+                               sigrelse(SIGCHLD);
+                               error("No more processes");
+                       }
+                       forked++;
+                       if (pid) {
+                               child = ochild; setintr = osetintr;
+                               haderr = ohaderr; didfds = odidfds;
+                               didcch = odidcch; SHIN = oSHIN;
+                               SHOUT = oSHOUT; SHDIAG = oSHDIAG;
+                               OLDSTD = oOLDSTD; tpgrp = otpgrp;
+                               xfree(Vsav); Vsav = 0;
+                               xfree(Vdp); Vdp = 0;
+                               xfree(Vav); Vav = 0;
+                               /* this is from pfork() */
+                               palloc(pid, t);
+                               sigrelse(SIGCHLD);
+                       } else {
+                               /* this is from pfork() */
+                               int pgrp;
+                               bool ignint = 0;
+
+                               if (setintr)
+                                       ignint =
+                                           (tpgrp == -1 && (t->t_dflg&FINT))
+                                           || gointr && eq(gointr, "-");
+                               pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
+                               child++;
+                               if (setintr) {
+                                       setintr = 0;
+                                       sigsys(SIGCHLD, SIG_DFL);
+                                       sigsys(SIGINT, ignint ? SIG_IGN : vffree);
+                                       sigsys(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
+                                       if (wanttty >= 0) {
+                                               sigsys(SIGTSTP, SIG_DFL);
+                                               sigsys(SIGTTIN, SIG_DFL);
+                                               sigsys(SIGTTOU, SIG_DFL);
+                                       }
+                                       sigsys(SIGTERM, parterm);
+                               } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
+                                       sigsys(SIGINT, SIG_IGN);
+                                       sigsys(SIGQUIT, SIG_IGN);
                                }
                                }
+                               if (wanttty > 0)
+                                       ioctl(FSHTTY, TIOCSPGRP, &pgrp);
+                               if (wanttty >= 0 && tpgrp >= 0)
+                                       setpgrp(0, pgrp);
+                               if (tpgrp > 0)
+                                       tpgrp = 0;
+                               if (t->t_dflg & FNOHUP)
+                                       sigsys(SIGHUP, SIG_IGN);
+                               if (t->t_dflg & FNICE)
+                                       nice(t->t_nice);
                        }
                        }
+
+               }
 #endif
                if (pid != 0) {
                        /*
 #endif
                if (pid != 0) {
                        /*
-                        * The parent path (or nobody does this if
-                        * (flags & FPAR), i.e. date in (set;date))
+                        * It would be better if we could wait for the
+                        * whole job when we knew the last process
+                        * had been started.  Pwait, in fact, does
+                        * wait for the whole job anyway, but this test
+                        * doesn't really express our intentions.
                         */
                         */
-                       if (didfds == 0 && (flags & FPIN))
+                       if (didfds==0 && t->t_dflg&FPIN)
                                close(pipein[0]), close(pipein[1]);
                                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;
+                       if ((t->t_dflg & (FPOU|FAND)) == 0)
+                               pwait();
+                       break;
                }
                }
-
-               /*
-                * Insure that this (child) shell doesn't muck on
-                */
-               child++;
-
-               /*
-                * If havent yet, finally set up the file descriptors.
-                */
                doio(t, pipein, pipeout);
                doio(t, pipein, pipeout);
-               if (flags & FPOU)
+               if (t->t_dflg & FPOU)
                        close(pipeout[0]), close(pipeout[1]);
 
                /*
                        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.
+                * Perform a builtin function.
+                * If we are not forked, arrange for possible stopping
                 */
                 */
-               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;
+               if (bifunc) {
+                       func(t, bifunc);
+                       if (forked)
+                               exitstat();
+                       break;
+               }
+               if (t->t_dtyp != TPAR) {
+                       doexec(t);
+                       /*NOTREACHED*/
                }
                }
-
                /*
                 * For () commands must put new 0,1,2 in FSH* and recurse
                 */
                /*
                 * 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 */
+               OLDSTD = dcopy(0, FOLDSTD);
+               SHOUT = dcopy(1, FSHOUT);
+               SHDIAG = dcopy(2, FSHDIAG);
+               close(SHIN), SHIN = -1;
+               didcch = 0, didfds = 0;
+               wanttty = -1;
+               t->t_dspr->t_dflg |= t->t_dflg & FINT;
+               execute(t->t_dspr, wanttty);
+               exitstat();
 
        case TFIL:
 
        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;
+               t->t_dcar->t_dflg |= FPOU |
+                   (t->t_dflg & (FPIN|FAND|FDIAG|FINT));
+               execute(t->t_dcar, wanttty, pipein, pv);
+               t->t_dcdr->t_dflg |= FPIN |
+                   (t->t_dflg & (FPOU|FAND|FPAR|FINT));
+               if (wanttty > 0)
+                       wanttty = 0;            /* got tty already */
+               execute(t->t_dcdr, wanttty, pv, pipeout);
+               break;
 
        case TLST:
 
        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;
+               if (t->t_dcar) {
+                       t->t_dcar->t_dflg |= t->t_dflg & FINT;
+                       execute(t->t_dcar, wanttty);
+                       /*
+                        * In strange case of A&B make a new job after A
+                        */
+                       if (t->t_dcar->t_dflg&FAND && t->t_dcdr &&
+                           (t->t_dcdr->t_dflg&FAND) == 0)
+                               pendjob();
+               }
+               if (t->t_dcdr) {
+                       t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
+                       execute(t->t_dcdr, wanttty);
+               }
+               break;
 
        case TOR:
        case TAND:
 
        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))
+               if (t->t_dcar) {
+                       t->t_dcar->t_dflg |= t->t_dflg & FINT;
+                       execute(t->t_dcar, wanttty);
+                       if ((getn(value("status")) == 0) != (t->t_dtyp == TAND))
                                return;
                }
                                return;
                }
-               if (t1 = t->t_dcdr)
-                       t1->t_dflg |= t->t_dflg & (FINT|FPAR), execute(t1);
-               return;
+               if (t->t_dcdr) {
+                       t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
+                       execute(t->t_dcdr, wanttty);
+               }
+               break;
        }
        }
+       /*
+        * Fall through for all breaks from switch
+        *
+        * If there will be no more executions of this
+        * command, flush all file descriptors.
+        * Places that turn on the FREDO bit are responsible
+        * for doing donefds after the last re-execution
+        */
+       if (didfds && !(t->t_dflg & FREDO))
+               donefds();
 }
 
 #ifdef VFORK
 }
 
 #ifdef VFORK
@@ -296,37 +290,36 @@ vffree()
 }
 #endif
 
 }
 #endif
 
+/*
+ * Perform io redirection.
+ * We may or maynot be forked here.
+ */
 doio(t, pipein, pipeout)
        register struct command *t;
        int *pipein, *pipeout;
 {
        register char *cp;
        register int flags = t->t_dflg;
 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 (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:
+       if ((flags & FHERE) == 0) {     /* FHERE already done */
+               close(0);
+               if (cp = t->t_dlef) {
+                       cp = globone(Dfix1(cp));
+                       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) && tpgrp == -1)
+                       close(0), open("/dev/null", 0);
+               else
+                       dup(OLDSTD);
+       }
        close(1);
        if (cp = t->t_drit) {
        close(1);
        if (cp = t->t_drit) {
-               cp = globone(dp = Dfix1(cp));
-               xfree(dp);
+               cp = globone(Dfix1(cp));
                xfree(cp);
                if ((flags & FCAT) && open(cp, 1) >= 0)
                        lseek(1, 0l, 2);
                xfree(cp);
                if ((flags & FCAT) && open(cp, 1) >= 0)
                        lseek(1, 0l, 2);
@@ -336,43 +329,19 @@ skipin:
                                        Perror(cp);
                                chkclob(cp);
                        }
                                        Perror(cp);
                                chkclob(cp);
                        }
-#ifdef V6
-                       if (creat(cp, 0644) < 0)
-                               Perror(cp);
-#else
                        if (creat(cp, 0666) < 0)
                                Perror(cp);
                        if (creat(cp, 0666) < 0)
                                Perror(cp);
-#endif
                }
                }
-       } else
-               dup((flags & FPOU) ? pipeout[1] : SHOUT);
+       } else if (flags & FPOU)
+               dup(pipeout[1]);
+       else
+               dup(SHOUT);
 
        close(2);
        dup((flags & FDIAG) ? 1 : SHDIAG);
        didfds = 1;
 }
 
 
        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;
 {
 mypipe(pv)
        register int *pv;
 {