Annotation of 3BSD/cmd/csh/sh.c, revision 1.1

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

unix.superglobalmegacorp.com

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