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

Defined functions

dosource defined in line 761; used 2 times
exit defined in line 855; used 5 times
gethdir defined in line 828; used 1 times
goodbye defined in line 529; used 4 times
importpath defined in line 373; used 1 times
initdesc defined in line 843; used 2 times
mailchk defined in line 785; used 1 times
main defined in line 26; never used
pintr defined in line 563; used 2 times
pintr1 defined in line 568; used 2 times
process defined in line 619; used 3 times
srccat defined in line 413; used 3 times
srcunit defined in line 428; used 2 times
untty defined in line 360; used 4 times

Defined variables

HIST defined in line 16; used 2 times
HISTSUB defined in line 17; never used
fast defined in line 23; used 4 times
jobargv defined in line 555; used 1 times
nexececho defined in line 21; used 2 times
nofile defined in line 18; used 9 times
nverbose defined in line 20; used 2 times
pathlist defined in line 15; used 1 times
  • in line 77
prompt defined in line 24; used 6 times
quitit defined in line 22; used 5 times
reenter defined in line 19; used 7 times
sccsid defined in line 1; never used
Last modified: 1982-12-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1908
Valid CSS Valid XHTML 1.0 Strict