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