|
|
1.1 ! root 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 = ¶ml; ! 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(¶ml), 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(¶ml) && !err && intty || ! 748: adrof("verbose")) { ! 749: haderr = 1; ! 750: prlex(¶ml); ! 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(¶ml); ! 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(¶ml); ! 784: ! 785: /* ! 786: * Parse the words of the input into a parse tree. ! 787: */ ! 788: t = syntax(paraml.next, ¶ml, 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(¶ml), 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.