Annotation of 43BSDReno/bin/csh/sh.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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