Annotation of researchv10no/lbin/csh/sh.c, revision 1.1.1.1

1.1       root        1: static char *sccsid = "@(#)sh.c 4.2 3/11/81";
                      2: 
                      3: #include "sh.h"
                      4: #include <sys/ioctl.h>
                      5: /*
                      6:  * C Shell
                      7:  *
                      8:  * Bill Joy, UC Berkeley, California, USA
                      9:  * October 1978, May 1980
                     10:  *
                     11:  * Jim Kulp, IIASA, Laxenburg, Austria
                     12:  * April 1980
                     13:  */
                     14: 
                     15: extern int     ntty_ld, tty_ld;
                     16: 
                     17: char   *pathlist[] =   { ".", "/usr/ucb", "/bin", "/usr/bin", 0 };
                     18: char   HIST = '!';
                     19: char   HISTSUB = '^';
                     20: bool   nofile;
                     21: bool   reenter;
                     22: bool   nverbose;
                     23: bool   nexececho;
                     24: bool   quitit;
                     25: bool   fast;
                     26: bool   prompt = 1;
                     27: 
                     28: main(c, av)
                     29:        int c;
                     30:        char **av;
                     31: {
                     32:        register char **v, *cp;
                     33:        register int f;
                     34: 
                     35:        settimes();                     /* Immed. estab. timing base */
                     36:        v = av;
                     37:        if (eq(v[0], "a.out"))          /* A.out's are quittable */
                     38:                quitit = 1;
                     39:        uid = getuid();
                     40:        loginsh = **v == '-';
                     41:        if (loginsh)
                     42:                time(&chktim);
                     43: 
                     44:        /*
                     45:         * Move the descriptors to safe places.
                     46:         * The variable didfds is 0 while we have only FSH* to work with.
                     47:         * When didfds is true, we have 0,1,2 and prefer to use these.
                     48:         */
                     49:        initdesc();
                     50: 
                     51:        /*
                     52:         * Initialize the shell variables.
                     53:         * ARGV and PROMPT are initialized later.
                     54:         * STATUS is also munged in several places.
                     55:         * CHILD is munged when forking/waiting
                     56:         */
                     57: 
                     58:        set("status", "0");
                     59:        dinit(cp = getenv("HOME"));     /* dinit thinks that HOME == cwd in a
                     60:                                         * login shell */
                     61:        if (cp == NOSTR)
                     62:                fast++;                 /* No home -> can't read scripts */
                     63:        else
                     64:                set("home", savestr(cp));
                     65:        /*
                     66:         * Grab other useful things from the environment.
                     67:         * Should we grab everything??
                     68:         */
                     69:        if ((cp = getenv("USER")) != NOSTR)
                     70:                set("user", savestr(cp));
                     71:        if ((cp = getenv("TERM")) != NOSTR)
                     72:                set("term", savestr(cp));
                     73:        /*
                     74:         * Re-initialize path if set in environment
                     75:         */
                     76:        if ((cp = getenv("PATH")) == NOSTR)
                     77:                set1("path", saveblk(pathlist), &shvhed);
                     78:        else {
                     79:                register unsigned i = 0;
                     80:                register char *dp;
                     81:                register char **pv;
                     82: 
                     83:                for (dp = cp; *dp; dp++)
                     84:                        if (*dp == ':')
                     85:                                i++;
                     86:                pv = (char **)calloc(i+2, sizeof (char **));
                     87:                for (dp = cp, i = 0; ;)
                     88:                        if (*dp == ':') {
                     89:                                *dp = 0;
                     90:                                pv[i++] = savestr(*cp ? cp : ".");
                     91:                                *dp++ = ':';
                     92:                                cp = dp;
                     93:                        } else if (*dp++ == 0) {
                     94:                                pv[i++] = savestr(*cp ? cp : ".");
                     95:                                break;
                     96:                        }
                     97:                pv[i] = 0;
                     98:                set1("path", pv, &shvhed);
                     99:        }
                    100:        set("shell", SHELLPATH);
                    101: 
                    102:        doldol = putn(getpid());                /* For $$ */
                    103:        shtemp = strspl("/tmp/sh", doldol);     /* For << */
                    104: 
                    105:        /*
                    106:         * Record the interrupt states from the parent process.
                    107:         * If the parent is non-interruptible our hand must be forced
                    108:         * or we (and our children) won't be either.
                    109:         * Our children inherit termination from our parent.
                    110:         * We catch it only if we are the login shell.
                    111:         */
                    112:        parintr = signal(SIGINT, SIG_IGN);      /* parents interruptibility */
                    113:        sigset(SIGINT, parintr);                        /* ... restore */
                    114:        parterm = signal(SIGTERM, SIG_IGN);     /* parents terminability */
                    115:        signal(SIGTERM, parterm);                       /* ... restore */
                    116: 
                    117:        /*
                    118:         * Process the arguments.
                    119:         *
                    120:         * Note that processing of -v/-x is actually delayed till after
                    121:         * script processing.
                    122:         *
                    123:         * We set the first character of our name to be '-' if we are
                    124:         * a shell running interruptible commands.  Many programs which
                    125:         * examine ps'es use this to filter such shells out.
                    126:         */
                    127:        c--, v++;
                    128:        while (c > 0 && (cp = v[0])[0] == '-') {
                    129:                do switch (*cp++) {
                    130: 
                    131:                case 0:                 /* -    Interruptible, no prompt */
                    132:                        prompt = 0;
                    133:                        setintr++;
                    134:                        nofile++;
                    135:                        break;
                    136: 
                    137:                case 'c':               /* -c   Command input from arg */
                    138:                        if (c == 1)
                    139:                                exit(0);
                    140:                        c--, v++;
                    141:                        arginp = v[0];
                    142:                        prompt = 0;
                    143:                        nofile++;
                    144:                        break;
                    145: 
                    146:                case 'e':               /* -e   Exit on any error */
                    147:                        exiterr++;
                    148:                        break;
                    149: 
                    150:                case 'f':               /* -f   Fast start */
                    151:                        fast++;
                    152:                        break;
                    153: 
                    154:                case 'i':               /* -i   Interactive, even if !intty */
                    155:                        intact++;
                    156:                        nofile++;
                    157:                        break;
                    158: 
                    159:                case 'n':               /* -n   Don't execute */
                    160:                        noexec++;
                    161:                        break;
                    162: 
                    163:                case 'q':               /* -q   (Undoc'd) ... die on quit */
                    164:                        quitit = 1;
                    165:                        break;
                    166: 
                    167:                case 's':               /* -s   read from std input */
                    168:                        nofile++;
                    169:                        break;
                    170: 
                    171:                case 't':               /* -t   read one line from input */
                    172:                        onelflg = 2;
                    173:                        prompt = 0;
                    174:                        nofile++;
                    175:                        break;
                    176: 
                    177:                case 'v':               /* -v   Echo hist expanded input */
                    178:                        nverbose = 1;                   /* ... later */
                    179:                        break;
                    180: 
                    181:                case 'x':               /* -x   Echo just before execution */
                    182:                        nexececho = 1;                  /* ... later */
                    183:                        break;
                    184: 
                    185:                case 'V':               /* -V   Echo hist expanded input */
                    186:                        setNS("verbose");               /* NOW! */
                    187:                        break;
                    188: 
                    189:                case 'X':               /* -X   Echo just before execution */
                    190:                        setNS("echo");                  /* NOW! */
                    191:                        break;
                    192: 
                    193:                } while (*cp);
                    194:                v++, c--;
                    195:        }
                    196: 
                    197:        if (quitit)                     /* With all due haste, for debugging */
                    198:                signal(SIGQUIT, SIG_DFL);
                    199: 
                    200:        /*
                    201:         * Unless prevented by -, -c, -i, -s, or -t, if there
                    202:         * are remaining arguments the first of them is the name
                    203:         * of a shell file from which to read commands.
                    204:         */
                    205:        if (nofile == 0 && c > 0) {
                    206:                nofile = open(v[0], 0);
                    207:                if (nofile < 0) {
                    208:                        child++;                /* So this ... */
                    209:                        Perror(v[0]);           /* ... doesn't return */
                    210:                }
                    211:                file = v[0];
                    212:                SHIN = dmove(nofile, FSHIN);    /* Replace FSHIN */
                    213:                prompt = 0;
                    214:                c--, v++;
                    215:        }
                    216:        /*
                    217:         * Consider input a tty if it really is or we are interactive.
                    218:         */
                    219:        intty = intact || isatty(SHIN);
                    220:        /*
                    221:         * Decide whether we should play with signals or not.
                    222:         * If we are explicitly told (via -i, or -) or we are a login
                    223:         * shell (arg0 starts with -) or the input and output are both
                    224:         * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
                    225:         * Note that in only the login shell is it likely that parent
                    226:         * may have set signals to be ignored
                    227:         */
                    228:        if (loginsh || intact || intty && isatty(SHOUT))
                    229:                setintr = 1;
                    230: #ifdef TELL
                    231:        settell();
                    232: #endif
                    233:        /*
                    234:         * Save the remaining arguments in argv.
                    235:         */
                    236:        setq("argv", v, &shvhed);
                    237: 
                    238:        /*
                    239:         * Set up the prompt.
                    240:         */
                    241:        if (prompt)
                    242:                set("prompt", uid == 0 ? "# " : "% ");
                    243: 
                    244:        /*
                    245:         * If we are an interactive shell, then start fiddling
                    246:         * with the signals; this is a tricky game.
                    247:         */
                    248:        shpgrp = getpgrp(0);
                    249:        opgrp = tpgrp = -1;
                    250:        oldisc = -1;
                    251:        if (setintr) {
                    252:                **av = '-';
                    253:                if (!quitit)            /* Wary! */
                    254:                        signal(SIGQUIT, SIG_IGN);
                    255:                sigset(SIGINT, pintr);
                    256:                sighold(SIGINT);
                    257:                signal(SIGTERM, SIG_IGN);
                    258:                if (quitit == 0 && arginp == 0) {
                    259:                        signal(SIGTSTP, SIG_IGN);
                    260:                        signal(SIGTTIN, SIG_IGN);
                    261:                        signal(SIGTTOU, SIG_IGN);
                    262:                        /*
                    263:                         * Wait till in foreground, in case someone
                    264:                         * stupidly runs
                    265:                         *      csh &
                    266:                         * dont want to try to grab away the tty.
                    267:                         */
                    268:                        if (isatty(FSHDIAG))
                    269:                                f = FSHDIAG;
                    270:                        else if (isatty(FSHOUT))
                    271:                                f = FSHOUT;
                    272:                        else if (isatty(OLDSTD))
                    273:                                f = OLDSTD;
                    274:                        else
                    275:                                f = -1;
                    276: retry:
                    277:                        if (ioctl(f, TIOCGPGRP, &tpgrp) == 0 && tpgrp != -1) {
                    278:                                int ldisc;
                    279:                                if (tpgrp != shpgrp) {
                    280:                                        int old = sigsys(SIGTTIN, SIG_DFL);
                    281:                                        kill(0, SIGTTIN);
                    282:                                        sigsys(SIGTTIN, old);
                    283:                                        goto retry;
                    284:                                }
                    285:                                if (0 > (oldisc = ioctl (f, FIOLOOKLD, 0)))
                    286:                                        goto notty;
                    287:                                if (oldisc == tty_ld) {
                    288:                                        ldisc = ntty_ld;
                    289:                                        if (0 > ioctl (f, FIOPOPLD, 0))
                    290:                                                goto notty;
                    291:                                        else if (0 > 
                    292:                                            ioctl (f, FIOPUSHLD, &ldisc, 0)) {
                    293:                                                ioctl(f, FIOPUSHLD, &oldisc, 0);
                    294:                                                goto notty;
                    295:                                        }
                    296:                                        printf (
                    297:                                            "Switching to new tty driver...\n");
                    298:                                } else {
                    299:                                        int xx = 0;
                    300:                                        /* test for newtty */
                    301:                                        if (ioctl(f, TIOCLBIS, &xx) > 0)
                    302:                                                oldisc = ntty_ld;
                    303:                                        else
                    304:                                                oldisc = -1;
                    305:                                }
                    306:                                opgrp = shpgrp;
                    307:                                shpgrp = getpid();
                    308:                                tpgrp = shpgrp;
                    309:                                ioctl(f, TIOCSPGRP, &shpgrp);
                    310:                                setpgrp(0, shpgrp);
                    311:                                dcopy(f, FSHTTY);
                    312:                                ioctl(FSHTTY, FIOCLEX, 0);
                    313:                        } else {
                    314: notty:
                    315:   printf("Warning: no access to tty; thus no job control in this shell...\n");
                    316:                                tpgrp = -1;
                    317:                        }
                    318:                }
                    319:        }
                    320:        sigset(SIGCHLD, pchild);                /* while signals not ready */
                    321: 
                    322:        /*
                    323:         * Set an exit here in case of an interrupt or error reading
                    324:         * the shell start-up scripts.
                    325:         */
                    326:        setexit();
                    327:        haderr = 0;             /* In case second time through */
                    328:        if (!fast && reenter == 0) {
                    329:                reenter++;
                    330:                /* Will have value("home") here because set fast if don't */
                    331:                srccat(value("home"), "/.cshrc");
                    332:                if (!fast && !arginp && !onelflg)
                    333:                        dohash();
                    334:                if (loginsh) {
                    335:                        int ldisc;
                    336:                        srccat(value("home"), "/.login");
                    337:                }
                    338:        }
                    339: 
                    340:        /*
                    341:         * Now are ready for the -v and -x flags
                    342:         */
                    343:        if (nverbose)
                    344:                setNS("verbose");
                    345:        if (nexececho)
                    346:                setNS("echo");
                    347: 
                    348:        /*
                    349:         * All the rest of the world is inside this call.
                    350:         * The argument to process indicates whether it should
                    351:         * catch "error unwinds".  Thus if we are a interactive shell
                    352:         * our call here will never return by being blown past on an error.
                    353:         */
                    354:        process(setintr);
                    355: 
                    356:        /*
                    357:         * Mop-up.
                    358:         */
                    359:        if (loginsh) {
                    360:                printf("logout\n");
                    361:                close(SHIN);
                    362:                child++;
                    363:                goodbye();
                    364:        }
                    365:        exitstat();
                    366: }
                    367: 
                    368: untty()
                    369: {
                    370: 
                    371:        if (tpgrp > 0) {
                    372:                setpgrp(0, opgrp);
                    373:                ioctl(FSHTTY, TIOCSPGRP, &opgrp);
                    374:                if (oldisc != -1 && oldisc != ntty_ld) {
                    375:                        printf("\nReverting to old tty driver...\n");
                    376:                        ioctl (FSHTTY, FIOPOPLD, 0);
                    377:                        ioctl (FSHTTY, FIOPUSHLD, &oldisc);
                    378:                }
                    379:        }
                    380: }
                    381: 
                    382: importpath(cp)
                    383: char *cp;
                    384: {
                    385:        register int i = 0;
                    386:        register char *dp;
                    387:        register char **pv;
                    388:        int c;
                    389:        static char dot[2] = {'.', 0};
                    390: 
                    391:        for (dp = cp; *dp; dp++)
                    392:                if (*dp == ':')
                    393:                        i++;
                    394:        /*
                    395:         * i+2 where i is the number of colons in the path.
                    396:         * There are i+1 directories in the path plus we need
                    397:         * room for a zero terminator.
                    398:         */
                    399:        pv = (char **) calloc(i+2, sizeof (char **));
                    400:        dp = cp;
                    401:        i = 0;
                    402:        if (*dp)
                    403:        for (;;) {
                    404:                if ((c = *dp) == ':' || c == 0) {
                    405:                        *dp = 0;
                    406:                        pv[i++] = savestr(*cp ? cp : dot);
                    407:                        if (c) {
                    408:                                cp = dp + 1;
                    409:                                *dp = ':';
                    410:                        } else
                    411:                                break;
                    412:                }
                    413:                dp++;
                    414:        }
                    415:        pv[i] = 0;
                    416:        set1("path", pv, &shvhed);
                    417: }
                    418: 
                    419: /*
                    420:  * Source to the file which is the catenation of the argument names.
                    421:  */
                    422: srccat(cp, dp)
                    423:        char *cp, *dp;
                    424: {
                    425:        register char *ep = strspl(cp, dp);
                    426:        register int unit = dmove(open(ep, 0), -1);
                    427: 
                    428:        /* ioctl(unit, FIOCLEX, NULL); */
                    429:        xfree(ep);
                    430: #ifdef INGRES
                    431:        srcunit(unit, 0);
                    432: #else
                    433:        srcunit(unit, 1);
                    434: #endif
                    435: }
                    436: 
                    437: /*
                    438:  * Source to a unit.  If onlyown it must be our file or our group or
                    439:  * we don't chance it. This occurs on ".cshrc"s and the like.
                    440:  */
                    441: srcunit(unit, onlyown)
                    442:        register int unit;
                    443:        bool onlyown;
                    444: {
                    445:        /* We have to push down a lot of state here */
                    446:        /* All this could go into a structure */
                    447:        int oSHIN = -1, oldintty = intty;
                    448:        struct whyle *oldwhyl = whyles;
                    449:        char *ogointr = gointr, *oarginp = arginp;
                    450:        char *oevalp = evalp, **oevalvec = evalvec;
                    451:        int oonelflg = onelflg;
                    452: #ifdef TELL
                    453:        bool otell = cantell;
                    454: #endif
                    455:        struct Bin saveB;
                    456: 
                    457:        /* The (few) real local variables */
                    458:        jmp_buf oldexit;
                    459:        int reenter;
                    460: 
                    461:        if (unit < 0)
                    462:                return;
                    463:        if (didfds)
                    464:                donefds();
                    465:        if (onlyown) {
                    466:                struct stat stb;
                    467: 
                    468:                if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_gid != getgid())) {
                    469:                        close(unit);
                    470:                        return;
                    471:                }
                    472:        }
                    473: 
                    474:        /*
                    475:         * There is a critical section here while we are pushing down the
                    476:         * input stream since we have stuff in different structures.
                    477:         * If we weren't careful an interrupt could corrupt SHIN's Bin
                    478:         * structure and kill the shell.
                    479:         *
                    480:         * We could avoid the critical region by grouping all the stuff
                    481:         * in a single structure and pointing at it to move it all at
                    482:         * once.  This is less efficient globally on many variable references
                    483:         * however.
                    484:         */
                    485:        getexit(oldexit);
                    486:        reenter = 0;
                    487:        if (setintr)
                    488:                sighold(SIGINT);
                    489:        setexit();
                    490:        reenter++;
                    491:        if (reenter == 1) {
                    492:                /* Setup the new values of the state stuff saved above */
                    493:                copy((char *)&saveB, (char *)&B, sizeof saveB);
                    494:                fbuf = (char **) 0;
                    495:                fseekp = feobp = fblocks = 0;
                    496:                oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
                    497:                intty = isatty(SHIN), whyles = 0, gointr = 0;
                    498:                evalvec = 0; evalp = 0;
                    499:                /*
                    500:                 * Now if we are allowing commands to be interrupted,
                    501:                 * we let ourselves be interrupted.
                    502:                 */
                    503:                if (setintr)
                    504:                        sigrelse(SIGINT);
                    505: #ifdef TELL
                    506:                settell();
                    507: #endif
                    508:                process(0);             /* 0 -> blow away on errors */
                    509:        }
                    510:        if (setintr)
                    511:                sigrelse(SIGINT);
                    512:        if (oSHIN >= 0) {
                    513:                register int i;
                    514: 
                    515:                /* We made it to the new state... free up its storage */
                    516:                /* This code could get run twice but xfree doesn't care */
                    517:                for (i = 0; i < fblocks; i++)
                    518:                        xfree(fbuf[i]);
                    519:                xfree((char *)fbuf);
                    520: 
                    521:                /* Reset input arena */
                    522:                copy((char *)&B, (char *)&saveB, sizeof B);
                    523: 
                    524:                close(SHIN), SHIN = oSHIN;
                    525:                arginp = oarginp, onelflg = oonelflg;
                    526:                evalp = oevalp, evalvec = oevalvec;
                    527:                intty = oldintty, whyles = oldwhyl, gointr = ogointr;
                    528: #ifdef TELL
                    529:                cantell = otell;
                    530: #endif
                    531:        }
                    532: 
                    533:        resexit(oldexit);
                    534:        /*
                    535:         * If process reset() (effectively an unwind) then
                    536:         * we must also unwind.
                    537:         */
                    538:        if (reenter >= 2)
                    539:                error(NOSTR);
                    540: }
                    541: 
                    542: goodbye()
                    543: {
                    544: 
                    545:        if (loginsh) {
                    546:                signal(SIGQUIT, SIG_IGN);
                    547:                sigset(SIGINT, SIG_IGN);
                    548:                signal(SIGTERM, SIG_IGN);
                    549:                setintr = 0;            /* No interrupts after "logout" */
                    550:                if (adrof("home"))
                    551:                        srccat(value("home"), "/.logout");
                    552:        }
                    553:        exitstat();
                    554: }
                    555: 
                    556: exitstat()
                    557: {
                    558: 
                    559:        /*
                    560:         * Note that if STATUS is corrupted (i.e. getn bombs)
                    561:         * then error will exit directly because we poke child here.
                    562:         * Otherwise we might continue unwarrantedly (sic).
                    563:         */
                    564:        child++;
                    565:        exit(getn(value("status")));
                    566: }
                    567: 
                    568: char   *jobargv[2] = { "jobs", 0 };
                    569: /*
                    570:  * Catch an interrupt, e.g. during lexical input.
                    571:  * If we are an interactive shell, we reset the interrupt catch
                    572:  * immediately.  In any case we drain the shell output,
                    573:  * and finally go through the normal error mechanism, which
                    574:  * gets a chance to make the shell go away.
                    575:  */
                    576: pintr()
                    577: {
                    578:        pintr1(1);
                    579: }
                    580: 
                    581: pintr1(wantnl)
                    582:        bool wantnl;
                    583: {
                    584:        register char **v;
                    585: 
                    586:        if (setintr) {
                    587:                sigrelse(SIGINT);
                    588:                if (pjobs) {
                    589:                        pjobs = 0;
                    590:                        printf("\n");
                    591:                        dojobs(jobargv);
                    592:                        bferr("Interrupted");
                    593:                }
                    594:        }
                    595:        if (setintr)
                    596:                sighold(SIGINT);
                    597:        sigrelse(SIGCHLD);
                    598:        draino();
                    599: 
                    600:        /*
                    601:         * If we have an active "onintr" then we search for the label.
                    602:         * Note that if one does "onintr -" then we shan't be interruptible
                    603:         * so we needn't worry about that here.
                    604:         */
                    605:        if (gointr) {
                    606:                search(ZGOTO, 0, gointr);
                    607:                timflg = 0;
                    608:                if (v = pargv)
                    609:                        pargv = 0, blkfree(v);
                    610:                if (v = gargv)
                    611:                        gargv = 0, blkfree(v);
                    612:                reset();
                    613:        } else if (intty && wantnl)
                    614:                printf("\n");           /* Some like this, others don't */
                    615:        error(NOSTR);
                    616: }
                    617: 
                    618: /*
                    619:  * Process is the main driving routine for the shell.
                    620:  * It runs all command processing, except for those within { ... }
                    621:  * in expressions (which is run by a routine evalav in sh.exp.c which
                    622:  * is a stripped down process), and `...` evaluation which is run
                    623:  * also by a subset of this code in sh.glob.c in the routine backeval.
                    624:  *
                    625:  * The code here is a little strange because part of it is interruptible
                    626:  * and hence freeing of structures appears to occur when none is necessary
                    627:  * if this is ignored.
                    628:  *
                    629:  * Note that if catch is not set then we will unwind on any error.
                    630:  * If an end-of-file occurs, we return.
                    631:  */
                    632: process(catch)
                    633:        bool catch;
                    634: {
                    635:        register char *cp;
                    636:        jmp_buf osetexit;
                    637:        struct command *t;
                    638: 
                    639:        getexit(osetexit);
                    640:        for (;;) {
                    641:                pendjob();
                    642:                paraml.next = paraml.prev = &paraml;
                    643:                paraml.word = "";
                    644:                t = 0;
                    645:                setexit();
                    646:                justpr = 0;                     /* A chance to execute */
                    647: 
                    648:                /*
                    649:                 * Interruptible during interactive reads
                    650:                 */
                    651:                if (setintr)
                    652:                        sigrelse(SIGINT);
                    653: 
                    654:                /*
                    655:                 * For the sake of reset()
                    656:                 */
                    657:                freelex(&paraml), freesyn(t), t = 0;
                    658: 
                    659:                if (haderr) {
                    660:                        if (!catch) {
                    661:                                /* unwind */
                    662:                                doneinp = 0;
                    663:                                resexit(osetexit);
                    664:                                reset();
                    665:                        }
                    666:                        haderr = 0;
                    667:                        /*
                    668:                         * Every error is eventually caught here or
                    669:                         * the shell dies.  It is at this
                    670:                         * point that we clean up any left-over open
                    671:                         * files, by closing all but a fixed number
                    672:                         * of pre-defined files.  Thus routines don't
                    673:                         * have to worry about leaving files open due
                    674:                         * to deeper errors... they will get closed here.
                    675:                         */
                    676:                        closem();
                    677:                        continue;
                    678:                }
                    679:                if (doneinp) {
                    680:                        doneinp = 0;
                    681:                        break;
                    682:                }
                    683:                if (chkstop)
                    684:                        chkstop--;
                    685:                if (neednote)
                    686:                        pnote();
                    687:                if (intty && evalvec == 0) {
                    688:                        mailchk();
                    689:                        /*
                    690:                         * If we are at the end of the input buffer
                    691:                         * then we are going to read fresh stuff.
                    692:                         * Otherwise, we are rereading input and don't
                    693:                         * need or want to prompt.
                    694:                         */
                    695:                        if (fseekp == feobp)
                    696:                                if (!whyles)
                    697:                                        for (cp = value("prompt"); *cp; cp++)
                    698:                                                if (*cp == HIST)
                    699:                                                        printf("%d", eventno + 1);
                    700:                                                else {
                    701:                                                        if (*cp == '\\' && cp[1] == HIST)
                    702:                                                                cp++;
                    703:                                                        putchar(*cp | QUOTE);
                    704:                                                }
                    705:                                else
                    706:                                        /*
                    707:                                         * Prompt for forward reading loop
                    708:                                         * body content.
                    709:                                         */
                    710:                                        printf("? ");
                    711:                        flush();
                    712:                }
                    713:                err = 0;
                    714: 
                    715:                /*
                    716:                 * Echo not only on VERBOSE, but also with history expansion.
                    717:                 * If there is a lexical error then we forego history echo.
                    718:                 */
                    719:                if (lex(&paraml) && !err && intty || adrof("verbose")) {
                    720:                        haderr = 1;
                    721:                        prlex(&paraml);
                    722:                        haderr = 0;
                    723:                }
                    724: 
                    725:                /*
                    726:                 * The parser may lose space if interrupted.
                    727:                 */
                    728:                if (setintr)
                    729:                        sighold(SIGINT);
                    730: 
                    731:                /*
                    732:                 * Save input text on the history list if it
                    733:                 * is from the terminal at the top level and not
                    734:                 * in a loop.
                    735:                 */
                    736:                if (catch && intty && !whyles)
                    737:                        savehist(&paraml);
                    738: 
                    739:                /*
                    740:                 * Print lexical error messages.
                    741:                 */
                    742:                if (err)
                    743:                        error(err);
                    744: 
                    745:                /*
                    746:                 * If had a history command :p modifier then
                    747:                 * this is as far as we should go
                    748:                 */
                    749:                if (justpr)
                    750:                        reset();
                    751: 
                    752:                alias(&paraml);
                    753: 
                    754:                /*
                    755:                 * Parse the words of the input into a parse tree.
                    756:                 */
                    757:                t = syntax(paraml.next, &paraml, 0);
                    758:                if (err)
                    759:                        error(err);
                    760: 
                    761:                /*
                    762:                 * Execute the parse tree
                    763:                 */
                    764:                execute(t, tpgrp);
                    765: 
                    766:                /*
                    767:                 * Made it!
                    768:                 */
                    769:                freelex(&paraml), freesyn(t);
                    770:        }
                    771:        resexit(osetexit);
                    772: }
                    773: 
                    774: dosource(t)
                    775:        register char **t;
                    776: {
                    777:        register char *f;
                    778:        register int u;
                    779: 
                    780:        t++;
                    781:        f = globone(*t);
                    782:        u = dmove(open(f, 0), -1);
                    783:        xfree(f);
                    784:        if (u < 0)
                    785:                Perror(f);
                    786:        srcunit(u, 0);
                    787: }
                    788: 
                    789: /*
                    790:  * Check for mail.
                    791:  * If we are a login shell, then we don't want to tell
                    792:  * about any mail file unless its been modified
                    793:  * after the time we started.
                    794:  * This prevents us from telling the user things he already
                    795:  * knows, since the login program insists on saying
                    796:  * "You have mail."
                    797:  */
                    798: mailchk()
                    799: {
                    800:        register struct varent *v;
                    801:        register char **vp;
                    802:        time_t t;
                    803:        int intvl, cnt;
                    804:        struct stat stb;
                    805:        bool new;
                    806: 
                    807:        v = adrof("mail");
                    808:        if (v == 0)
                    809:                return;
                    810:        time(&t);
                    811:        vp = v->vec;
                    812:        cnt = blklen(vp);
                    813:        intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
                    814:        if (intvl < 1)
                    815:                intvl = 1;
                    816:        if (chktim + intvl > t)
                    817:                return;
                    818:        for (; *vp; vp++) {
                    819:                if (stat(*vp, &stb) < 0)
                    820:                        continue;
                    821:                new = stb.st_mtime > time0;
                    822:                if (stb.st_size == 0 || stb.st_atime > stb.st_mtime ||
                    823:                    (stb.st_atime < chktim && stb.st_mtime < chktim) ||
                    824:                    loginsh && !new)
                    825:                        continue;
                    826:                if (cnt == 1)
                    827:                        printf("You have %smail.\n", new ? "new " : "");
                    828:                else
                    829:                        printf("%s in %s.\n", new ? "New mail" : "Mail", *vp);
                    830:        }
                    831:        chktim = t;
                    832: }
                    833: 
                    834: #include <pwd.h>
                    835: /*
                    836:  * Extract a home directory from the password file
                    837:  * The argument points to a buffer where the name of the
                    838:  * user whose home directory is sought is currently.
                    839:  * We write the home directory of the user back there.
                    840:  */
                    841: gethdir(home)
                    842:        char *home;
                    843: {
                    844:        register struct passwd *pp = getpwnam(home);
                    845: 
                    846:        if (pp == 0)
                    847:                return (1);
                    848:        strcpy(home, pp->pw_dir);
                    849:        return (0);
                    850: }
                    851: 
                    852: /*
                    853:  * Move the initial descriptors to their eventual
                    854:  * resting places, closin all other units.
                    855:  */
                    856: initdesc()
                    857: {
                    858: 
                    859:        didcch = 0;                     /* Havent closed for child */
                    860:        didfds = 0;                     /* 0, 1, 2 aren't set up */
                    861:        SHIN = dcopy(0, FSHIN);
                    862:        SHOUT = dcopy(1, FSHOUT);
                    863:        SHDIAG = dcopy(2, FSHDIAG);
                    864:        OLDSTD = dcopy(SHIN, FOLDSTD);
                    865:        closem();
                    866: }
                    867: 
                    868: exit(i)
                    869:        int i;
                    870: {
                    871: 
                    872:        untty();
                    873: #ifdef PROF
                    874:        IEH3exit(i);
                    875: #else
                    876:        _exit(i);
                    877: #endif
                    878: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.