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
dosource defined in line 806; used 3 times
exit defined in line 908; never used
gethdir defined in line 881; used 1 times
goodbye defined in line 575; used 4 times
importpath defined in line 378; used 2 times
initdesc defined in line 896; used 2 times
mailchk defined in line 838; used 1 times
main defined in line 41; never used
phup defined in line 607; used 4 times
pintr defined in line 621; used 2 times
pintr1 defined in line 626; used 2 times
printprompt defined in line 919; used 2 times
process defined in line 677; used 3 times
rechist defined in line 549; 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 613; 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: 1991-08-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6612
Valid CSS Valid XHTML 1.0 Strict