1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley Software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char *sccsid = "@(#)sh.c	5.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, omask;
 459: 
 460:     if (unit < 0)
 461:         return;
 462:     if (didfds)
 463:         donefds();
 464:     if (onlyown) {
 465:         struct stat stb;
 466: 
 467:         if (fstat(unit, &stb) < 0 ||
 468:             (stb.st_uid != uid && stb.st_gid != getgid())) {
 469:             (void) close(unit);
 470:             return;
 471:         }
 472:     }
 473: 
 474:     /*
 475: 	 * There is a critical section here while we are pushing down the
 476: 	 * input stream since we have stuff in different structures.
 477: 	 * If we weren't careful an interrupt could corrupt SHIN's Bin
 478: 	 * structure and kill the shell.
 479: 	 *
 480: 	 * We could avoid the critical region by grouping all the stuff
 481: 	 * in a single structure and pointing at it to move it all at
 482: 	 * once.  This is less efficient globally on many variable references
 483: 	 * however.
 484: 	 */
 485:     getexit(oldexit);
 486:     reenter = 0;
 487:     if (setintr)
 488:         omask = sigblock(sigmask(SIGINT));
 489:     setexit();
 490:     reenter++;
 491:     if (reenter == 1) {
 492:         /* Setup the new values of the state stuff saved above */
 493:         copy((char *)&saveB, (char *)&B, sizeof saveB);
 494:         fbuf = (char **) 0;
 495:         fseekp = feobp = fblocks = 0;
 496:         oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
 497:         intty = isatty(SHIN), whyles = 0, gointr = 0;
 498:         evalvec = 0; evalp = 0;
 499:         enterhist = hflg;
 500:         if (enterhist)
 501:             HIST = '\0';
 502:         /*
 503: 		 * Now if we are allowing commands to be interrupted,
 504: 		 * we let ourselves be interrupted.
 505: 		 */
 506:         if (setintr)
 507:             (void) sigsetmask(omask);
 508: #ifdef TELL
 509:         settell();
 510: #endif
 511:         process(0);     /* 0 -> blow away on errors */
 512:     }
 513:     if (setintr)
 514:         (void) sigsetmask(omask);
 515:     if (oSHIN >= 0) {
 516:         register int i;
 517: 
 518:         /* We made it to the new state... free up its storage */
 519:         /* This code could get run twice but xfree doesn't care */
 520:         for (i = 0; i < fblocks; i++)
 521:             xfree(fbuf[i]);
 522:         xfree((char *)fbuf);
 523: 
 524:         /* Reset input arena */
 525:         copy((char *)&B, (char *)&saveB, sizeof B);
 526: 
 527:         (void) close(SHIN), SHIN = oSHIN;
 528:         arginp = oarginp, onelflg = oonelflg;
 529:         evalp = oevalp, evalvec = oevalvec;
 530:         intty = oldintty, whyles = oldwhyl, gointr = ogointr;
 531:         if (enterhist)
 532:             HIST = OHIST;
 533:         enterhist = oenterhist;
 534: #ifdef TELL
 535:         cantell = otell;
 536: #endif
 537:     }
 538: 
 539:     resexit(oldexit);
 540:     /*
 541: 	 * If process reset() (effectively an unwind) then
 542: 	 * we must also unwind.
 543: 	 */
 544:     if (reenter >= 2)
 545:         error(NOSTR);
 546: }
 547: 
 548: rechist()
 549: {
 550:     char buf[BUFSIZ];
 551:     int fp, ftmp, oldidfds;
 552: 
 553:     if (!fast) {
 554:         if (value("savehist")[0] == '\0')
 555:             return;
 556:         (void) strcpy(buf, value("home"));
 557:         (void) strcat(buf, "/.history");
 558:         fp = creat(buf, 0666);
 559:         if (fp == -1)
 560:             return;
 561:         oldidfds = didfds;
 562:         didfds = 0;
 563:         ftmp = SHOUT;
 564:         SHOUT = fp;
 565:         (void) strcpy(buf, value("savehist"));
 566:         dumphist[2] = buf;
 567:         dohist(dumphist);
 568:         (void) close(fp);
 569:         SHOUT = ftmp;
 570:         didfds = oldidfds;
 571:     }
 572: }
 573: 
 574: goodbye()
 575: {
 576:     if (loginsh) {
 577:         (void) signal(SIGQUIT, SIG_IGN);
 578:         (void) signal(SIGINT, SIG_IGN);
 579:         (void) signal(SIGTERM, SIG_IGN);
 580:         setintr = 0;        /* No interrupts after "logout" */
 581:         if (adrof("home"))
 582:             srccat(value("home"), "/.logout");
 583:     }
 584:     rechist();
 585:     exitstat();
 586: }
 587: 
 588: exitstat()
 589: {
 590: 
 591: #ifdef PROF
 592:     monitor(0);
 593: #endif
 594:     /*
 595: 	 * Note that if STATUS is corrupted (i.e. getn bombs)
 596: 	 * then error will exit directly because we poke child here.
 597: 	 * Otherwise we might continue unwarrantedly (sic).
 598: 	 */
 599:     child++;
 600:     exit(getn(value("status")));
 601: }
 602: 
 603: /*
 604:  * in the event of a HUP we want to save the history
 605:  */
 606: phup()
 607: {
 608:     rechist();
 609:     exit(1);
 610: }
 611: 
 612: char    *jobargv[2] = { "jobs", 0 };
 613: /*
 614:  * Catch an interrupt, e.g. during lexical input.
 615:  * If we are an interactive shell, we reset the interrupt catch
 616:  * immediately.  In any case we drain the shell output,
 617:  * and finally go through the normal error mechanism, which
 618:  * gets a chance to make the shell go away.
 619:  */
 620: pintr()
 621: {
 622:     pintr1(1);
 623: }
 624: 
 625: pintr1(wantnl)
 626:     bool wantnl;
 627: {
 628:     register char **v;
 629:     int omask;
 630: 
 631:     omask = sigblock(0);
 632:     if (setintr) {
 633:         (void) sigsetmask(omask & ~sigmask(SIGINT));
 634:         if (pjobs) {
 635:             pjobs = 0;
 636:             printf("\n");
 637:             dojobs(jobargv);
 638:             bferr("Interrupted");
 639:         }
 640:     }
 641:     (void) sigsetmask(omask & ~sigmask(SIGCHLD));
 642:     draino();
 643: 
 644:     /*
 645: 	 * If we have an active "onintr" then we search for the label.
 646: 	 * Note that if one does "onintr -" then we shan't be interruptible
 647: 	 * so we needn't worry about that here.
 648: 	 */
 649:     if (gointr) {
 650:         search(ZGOTO, 0, gointr);
 651:         timflg = 0;
 652:         if (v = pargv)
 653:             pargv = 0, blkfree(v);
 654:         if (v = gargv)
 655:             gargv = 0, blkfree(v);
 656:         reset();
 657:     } else if (intty && wantnl)
 658:         printf("\n");       /* Some like this, others don't */
 659:     error(NOSTR);
 660: }
 661: 
 662: /*
 663:  * Process is the main driving routine for the shell.
 664:  * It runs all command processing, except for those within { ... }
 665:  * in expressions (which is run by a routine evalav in sh.exp.c which
 666:  * is a stripped down process), and `...` evaluation which is run
 667:  * also by a subset of this code in sh.glob.c in the routine backeval.
 668:  *
 669:  * The code here is a little strange because part of it is interruptible
 670:  * and hence freeing of structures appears to occur when none is necessary
 671:  * if this is ignored.
 672:  *
 673:  * Note that if catch is not set then we will unwind on any error.
 674:  * If an end-of-file occurs, we return.
 675:  */
 676: process(catch)
 677:     bool catch;
 678: {
 679:     jmp_buf osetexit;
 680:     register struct command *t;
 681: 
 682:     getexit(osetexit);
 683:     for (;;) {
 684:         pendjob();
 685:         paraml.next = paraml.prev = &paraml;
 686:         paraml.word = "";
 687:         t = 0;
 688:         setexit();
 689:         justpr = enterhist; /* execute if not entering history */
 690: 
 691:         /*
 692: 		 * Interruptible during interactive reads
 693: 		 */
 694:         if (setintr)
 695:             (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
 696: 
 697:         /*
 698: 		 * For the sake of reset()
 699: 		 */
 700:         freelex(&paraml), freesyn(t), t = 0;
 701: 
 702:         if (haderr) {
 703:             if (!catch) {
 704:                 /* unwind */
 705:                 doneinp = 0;
 706:                 resexit(osetexit);
 707:                 reset();
 708:             }
 709:             haderr = 0;
 710:             /*
 711: 			 * Every error is eventually caught here or
 712: 			 * the shell dies.  It is at this
 713: 			 * point that we clean up any left-over open
 714: 			 * files, by closing all but a fixed number
 715: 			 * of pre-defined files.  Thus routines don't
 716: 			 * have to worry about leaving files open due
 717: 			 * to deeper errors... they will get closed here.
 718: 			 */
 719:             closem();
 720:             continue;
 721:         }
 722:         if (doneinp) {
 723:             doneinp = 0;
 724:             break;
 725:         }
 726:         if (chkstop)
 727:             chkstop--;
 728:         if (neednote)
 729:             pnote();
 730:         if (intty && prompt && evalvec == 0) {
 731:             mailchk();
 732:             /*
 733: 			 * If we are at the end of the input buffer
 734: 			 * then we are going to read fresh stuff.
 735: 			 * Otherwise, we are rereading input and don't
 736: 			 * need or want to prompt.
 737: 			 */
 738:             if (fseekp == feobp)
 739:                 printprompt();
 740:         }
 741:         err = 0;
 742: 
 743:         /*
 744: 		 * Echo not only on VERBOSE, but also with history expansion.
 745: 		 * If there is a lexical error then we forego history echo.
 746: 		 */
 747:         if (lex(&paraml) && !err && intty ||
 748:             adrof("verbose")) {
 749:             haderr = 1;
 750:             prlex(&paraml);
 751:             haderr = 0;
 752:         }
 753: 
 754:         /*
 755: 		 * The parser may lose space if interrupted.
 756: 		 */
 757:         if (setintr)
 758:             (void) sigblock(sigmask(SIGINT));
 759: 
 760:         /*
 761: 		 * Save input text on the history list if
 762: 		 * reading in old history, or it
 763: 		 * is from the terminal at the top level and not
 764: 		 * in a loop.
 765: 		 */
 766:         if (enterhist || catch && intty && !whyles)
 767:             savehist(&paraml);
 768: 
 769:         /*
 770: 		 * Print lexical error messages, except when sourcing
 771: 		 * history lists.
 772: 		 */
 773:         if (!enterhist && err)
 774:             error(err);
 775: 
 776:         /*
 777: 		 * If had a history command :p modifier then
 778: 		 * this is as far as we should go
 779: 		 */
 780:         if (justpr)
 781:             reset();
 782: 
 783:         alias(&paraml);
 784: 
 785:         /*
 786: 		 * Parse the words of the input into a parse tree.
 787: 		 */
 788:         t = syntax(paraml.next, &paraml, 0);
 789:         if (err)
 790:             error(err);
 791: 
 792:         /*
 793: 		 * Execute the parse tree
 794: 		 */
 795:         execute(t, tpgrp);
 796: 
 797:         /*
 798: 		 * Made it!
 799: 		 */
 800:         freelex(&paraml), freesyn(t);
 801:     }
 802:     resexit(osetexit);
 803: }
 804: 
 805: dosource(t)
 806:     register char **t;
 807: {
 808:     register char *f;
 809:     register int u;
 810:     bool hflg = 0;
 811:     char buf[BUFSIZ];
 812: 
 813:     t++;
 814:     if (*t && eq(*t, "-h")) {
 815:         t++;
 816:         hflg++;
 817:     }
 818:     (void) strcpy(buf, *t);
 819:     f = globone(buf);
 820:     u = dmove(open(f, 0), -1);
 821:     xfree(f);
 822:     if (u < 0 && !hflg)
 823:         Perror(f);
 824:     (void) ioctl(u, FIOCLEX, (char *)0);
 825:     srcunit(u, 0, hflg);
 826: }
 827: 
 828: /*
 829:  * Check for mail.
 830:  * If we are a login shell, then we don't want to tell
 831:  * about any mail file unless its been modified
 832:  * after the time we started.
 833:  * This prevents us from telling the user things he already
 834:  * knows, since the login program insists on saying
 835:  * "You have mail."
 836:  */
 837: mailchk()
 838: {
 839:     register struct varent *v;
 840:     register char **vp;
 841:     time_t t;
 842:     int intvl, cnt;
 843:     struct stat stb;
 844:     bool new;
 845: 
 846:     v = adrof("mail");
 847:     if (v == 0)
 848:         return;
 849:     (void) time(&t);
 850:     vp = v->vec;
 851:     cnt = blklen(vp);
 852:     intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
 853:     if (intvl < 1)
 854:         intvl = 1;
 855:     if (chktim + intvl > t)
 856:         return;
 857:     for (; *vp; vp++) {
 858:         if (stat(*vp, &stb) < 0)
 859:             continue;
 860:         new = stb.st_mtime > time0.tv_sec;
 861:         if (stb.st_size == 0 || stb.st_atime > stb.st_mtime ||
 862:             (stb.st_atime < chktim && stb.st_mtime < chktim) ||
 863:             loginsh && !new)
 864:             continue;
 865:         if (cnt == 1)
 866:             printf("You have %smail.\n", new ? "new " : "");
 867:         else
 868:             printf("%s in %s.\n", new ? "New mail" : "Mail", *vp);
 869:     }
 870:     chktim = t;
 871: }
 872: 
 873: #include <pwd.h>
 874: /*
 875:  * Extract a home directory from the password file
 876:  * The argument points to a buffer where the name of the
 877:  * user whose home directory is sought is currently.
 878:  * We write the home directory of the user back there.
 879:  */
 880: gethdir(home)
 881:     char *home;
 882: {
 883:     register struct passwd *pp = getpwnam(home);
 884: 
 885:     if (pp == 0)
 886:         return (1);
 887:     (void) strcpy(home, pp->pw_dir);
 888:     return (0);
 889: }
 890: 
 891: /*
 892:  * Move the initial descriptors to their eventual
 893:  * resting places, closin all other units.
 894:  */
 895: initdesc()
 896: {
 897: 
 898:     didfds = 0;         /* 0, 1, 2 aren't set up */
 899:     (void) ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, (char *)0);
 900:     (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, (char *)0);
 901:     (void) ioctl(SHDIAG = dcopy(2, FSHDIAG), FIOCLEX, (char *)0);
 902:     (void) ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, (char *)0);
 903:     closem();
 904: }
 905: 
 906: #ifdef PROF
 907: done(i)
 908: #else
 909: exit(i)
 910: #endif
 911:     int i;
 912: {
 913: 
 914:     untty();
 915:     _exit(i);
 916: }
 917: 
 918: printprompt()
 919: {
 920:     register char *cp;
 921: 
 922:     if (!whyles) {
 923:         for (cp = value("prompt"); *cp; cp++)
 924:             if (*cp == HIST)
 925:                 printf("%d", eventno + 1);
 926:             else {
 927:                 if (*cp == '\\' && cp[1] == HIST)
 928:                     cp++;
 929:                 putchar(*cp | QUOTE);
 930:             }
 931:     } else
 932:         /*
 933: 		 * Prompt for forward reading loop
 934: 		 * body content.
 935: 		 */
 936:         printf("? ");
 937:     flush();
 938: }

Defined functions

done defined in line 907; used 1 times
dosource defined in line 805; used 3 times
exit defined in line 907; never used
gethdir defined in line 880; used 1 times
goodbye defined in line 574; used 4 times
importpath defined in line 378; used 2 times
initdesc defined in line 895; used 2 times
mailchk defined in line 837; used 1 times
main defined in line 41; never used
phup defined in line 606; used 4 times
pintr defined in line 620; used 2 times
pintr1 defined in line 625; used 2 times
printprompt defined in line 918; used 2 times
process defined in line 676; used 3 times
rechist defined in line 548; used 5 times
srccat defined in line 418; used 3 times
srcunit defined in line 437; used 3 times
untty defined in line 363; used 4 times

Defined variables

HIST defined in line 26; used 5 times
HISTSUB defined in line 27; never used
batch defined in line 34; used 3 times
dumphist defined in line 24; used 2 times
enterhist defined in line 36; used 8 times
fast defined in line 33; used 5 times
jobargv defined in line 612; used 1 times
loadhist defined in line 25; used 1 times
nexececho defined in line 31; used 2 times
nofile defined in line 28; used 8 times
nverbose defined in line 30; used 2 times
pathlist defined in line 23; used 1 times
  • in line 91
prompt defined in line 35; used 5 times
quitit defined in line 32; used 5 times
reenter defined in line 29; used 7 times
sccsid defined in line 8; never used
Last modified: 1986-03-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3001
Valid CSS Valid XHTML 1.0 Strict