# 2.11BSD#431 - /usr/src/bin/csh/sh.c

##### Functions

    done              X
    dosource          X
    exit              X
    exitstat          X
    gethdir           X
    goodbye           X
    importpath        X
    initdesc          X
    mailchk           X
    main              X
    phup              X
    pintr             X
    pintr1            X
    printprompt       X
    process           X
    rechist           X
    srccat            X
    srcunit           X
    untty             X

##### Variables

    HIST              X
    HISTSUB           X
    batch             X
    dumphist          X
    enterhist         X
    fast              X
    jobargv           X
    loadhist          X
    nexececho         X
    nofile            X
    nverbose          X
    pathlist          X
    prompt            X
    quitit            X
    reenter           X

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

#### Defined functions

done defined in line 908; used 1 times

- in /usr/src/bin/csh/sh.local.h line 50

dosource defined in line 806; used 3 times

- in line 331
- in /usr/src/bin/csh/sh.init.c line 57, 149

exit defined in line 908; never used
exitstat defined in line 589; used 8 times

- in line 360, 586
- in /usr/src/bin/csh/sh.exp.c line 413
- in /usr/src/bin/csh/sh.glob.c line 672
- in /usr/src/bin/csh/sh.lex.c line 1117
- in /usr/src/bin/csh/sh.proc.c line 241
- in /usr/src/bin/csh/sh.sem.c line 242, 261

gethdir defined in line 881; used 1 times

- in /usr/src/bin/csh/sh.glob.c line 141

goodbye defined in line 575; used 4 times

- in line 357
- in /usr/src/bin/csh/sh.func.c line 168
- in /usr/src/bin/csh/sh.init.c line 72, 97

importpath defined in line 378; used 2 times

- in line 93
- in /usr/src/bin/csh/sh.func.c line 787

initdesc defined in line 896; used 2 times

- in line 63
- in /usr/src/bin/csh/sh.glob.c line 655

mailchk defined in line 838; used 1 times

- in line 732

main defined in line 41; never used
phup defined in line 607; used 4 times

- in line 113-115(3)
- in /usr/src/bin/csh/sh.h line 429

pintr defined in line 621; used 2 times

- in line 256
- in /usr/src/bin/csh/sh.h line 430

pintr1 defined in line 626; used 2 times

- in line 623
- in /usr/src/bin/csh/sh.proc.c line 229

printprompt defined in line 919; used 2 times

- in line 740
- in /usr/src/bin/csh/sh.file.c line 573

process defined in line 677; used 3 times

- in line 348, 512
- in /usr/src/bin/csh/sh.func.c line 1144

rechist defined in line 549; used 5 times

- in line 359, 585, 609
- in /usr/src/bin/csh/sh.exec.c line 233
- in /usr/src/bin/csh/sh.func.c line 176

srccat defined in line 418; used 3 times

- in line 325-329(2), 583

srcunit defined in line 437; used 3 times

- in line 427-429(2), 826

untty defined in line 363; used 4 times

- in line 915
- in /usr/src/bin/csh/sh.func.c line 179, 193, 1091

#### Defined variables

HIST defined in line 26; used 5 times

- in line 450, 502, 533, 925-928(2)

HISTSUB defined in line 27; never used
batch defined in line 34; used 3 times

- in line 125-129(2), 212

dumphist defined in line 24; used 2 times

- in line 567-568(2)

enterhist defined in line 36; used 8 times

- in line 449, 500-501(2), 532-534(2), 690, 767, 774

fast defined in line 33; used 5 times

- in line 76, 146, 322-326(2), 554

jobargv defined in line 613; used 1 times

- in line 638

loadhist defined in line 25; used 1 times

- in line 331

nexececho defined in line 31; used 2 times

- in line 177, 339

nofile defined in line 28; used 8 times

- in line 138, 151, 163, 169, 200-207(4)

nverbose defined in line 30; used 2 times

- in line 173, 337

pathlist defined in line 23; used 1 times

- in line 91

prompt defined in line 35; used 5 times

- in line 137, 168, 209, 242, 731

quitit defined in line 32; used 5 times

- in line 52, 159, 192, 254-259(2)

reenter defined in line 29; used 7 times

- in line 322-323(2), 458, 487-492(3), 545

sccsid defined in line 8; never used

Last modified: 1991-08-31 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3014 |