Annotation of 40BSD/cmd/oldcsh/sh.c, revision 1.1.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.