|
|
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.14 (Berkeley) 6/30/90"; ! 9: #endif ! 10: ! 11: #include "sh.h" ! 12: #include <sys/ioctl.h> ! 13: #include <sys/file.h> ! 14: #include "pathnames.h" ! 15: ! 16: /* ! 17: * C Shell ! 18: * ! 19: * Bill Joy, UC Berkeley, California, USA ! 20: * October 1978, May 1980 ! 21: * ! 22: * Jim Kulp, IIASA, Laxenburg, Austria ! 23: * April 1980 ! 24: */ ! 25: ! 26: char *pathlist[] = { ".", _PATH_BIN, _PATH_USRBIN, 0 }; ! 27: char *dumphist[] = { "history", "-h", 0, 0 }; ! 28: char *loadhist[] = { "source", "-h", "~/.history", 0 }; ! 29: char HIST = '!'; ! 30: char HISTSUB = '^'; ! 31: bool mflag; ! 32: bool nofile; ! 33: bool reenter; ! 34: bool nverbose; ! 35: bool nexececho; ! 36: bool quitit; ! 37: bool fast; ! 38: bool batch; ! 39: bool prompt = 1; ! 40: bool enterhist = 0; ! 41: ! 42: extern gid_t getegid(), getgid(); ! 43: extern uid_t geteuid(), getuid(); ! 44: ! 45: main(c, av) ! 46: int c; ! 47: char **av; ! 48: { ! 49: register char **v, *cp; ! 50: register int f; ! 51: struct sigvec osv; ! 52: ! 53: settimes(); /* Immed. estab. timing base */ ! 54: v = av; ! 55: if (eq(v[0], "a.out")) /* A.out's are quittable */ ! 56: quitit = 1; ! 57: uid = getuid(); ! 58: loginsh = **v == '-' && c == 1; ! 59: if (loginsh) ! 60: (void) time(&chktim); ! 61: ! 62: /* ! 63: * Move the descriptors to safe places. ! 64: * The variable didfds is 0 while we have only FSH* to work with. ! 65: * When didfds is true, we have 0,1,2 and prefer to use these. ! 66: */ ! 67: initdesc(); ! 68: ! 69: /* ! 70: * Initialize the shell variables. ! 71: * ARGV and PROMPT are initialized later. ! 72: * STATUS is also munged in several places. ! 73: * CHILD is munged when forking/waiting ! 74: */ ! 75: ! 76: set("status", "0"); ! 77: dinit(cp = getenv("HOME")); /* dinit thinks that HOME == cwd in a ! 78: * login shell */ ! 79: if (cp == NOSTR) ! 80: fast++; /* No home -> can't read scripts */ ! 81: else ! 82: set("home", savestr(cp)); ! 83: /* ! 84: * Grab other useful things from the environment. ! 85: * Should we grab everything?? ! 86: */ ! 87: if ((cp = getenv("USER")) != NOSTR) ! 88: set("user", savestr(cp)); ! 89: if ((cp = getenv("TERM")) != NOSTR) ! 90: set("term", savestr(cp)); ! 91: /* ! 92: * Re-initialize path if set in environment ! 93: */ ! 94: if ((cp = getenv("PATH")) == NOSTR) ! 95: set1("path", saveblk(pathlist), &shvhed); ! 96: else ! 97: importpath(cp); ! 98: set("shell", _PATH_CSHELL); ! 99: ! 100: doldol = putn(getpid()); /* For $$ */ ! 101: shtemp = strspl("/tmp/sh", doldol); /* For << */ ! 102: ! 103: /* ! 104: * Record the interrupt states from the parent process. ! 105: * If the parent is non-interruptible our hand must be forced ! 106: * or we (and our children) won't be either. ! 107: * Our children inherit termination from our parent. ! 108: * We catch it only if we are the login shell. ! 109: */ ! 110: /* parents interruptibility */ ! 111: (void) sigvec(SIGINT, (struct sigvec *)0, &osv); ! 112: parintr = osv.sv_handler; ! 113: /* parents terminability */ ! 114: (void) sigvec(SIGTERM, (struct sigvec *)0, &osv); ! 115: parterm = osv.sv_handler; ! 116: if (loginsh) { ! 117: sig_t phup; ! 118: ! 119: (void) signal(SIGHUP, phup); /* exit processing on HUP */ ! 120: (void) signal(SIGXCPU, phup); /* ...and on XCPU */ ! 121: (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */ ! 122: } ! 123: ! 124: /* ! 125: * Process the arguments. ! 126: * ! 127: * Note that processing of -v/-x is actually delayed till after ! 128: * script processing. ! 129: */ ! 130: c--, v++; ! 131: while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) { ! 132: do switch (*cp++) { ! 133: ! 134: case 'b': /* -b Next arg is input file */ ! 135: batch++; ! 136: break; ! 137: ! 138: case 'c': /* -c Command input from arg */ ! 139: if (c == 1) ! 140: exit(0); ! 141: c--, v++; ! 142: arginp = v[0]; ! 143: prompt = 0; ! 144: nofile++; ! 145: break; ! 146: ! 147: case 'e': /* -e Exit on any error */ ! 148: exiterr++; ! 149: break; ! 150: ! 151: case 'f': /* -f Fast start */ ! 152: fast++; ! 153: break; ! 154: ! 155: case 'i': /* -i Interactive, even if !intty */ ! 156: intact++; ! 157: nofile++; ! 158: break; ! 159: ! 160: case 'm': /* -m read .cshrc (from su) */ ! 161: mflag++; ! 162: break; ! 163: ! 164: case 'n': /* -n Don't execute */ ! 165: noexec++; ! 166: break; ! 167: ! 168: case 'q': /* -q (Undoc'd) ... die on quit */ ! 169: quitit = 1; ! 170: break; ! 171: ! 172: case 's': /* -s Read from std input */ ! 173: nofile++; ! 174: break; ! 175: ! 176: case 't': /* -t Read one line from input */ ! 177: onelflg = 2; ! 178: prompt = 0; ! 179: nofile++; ! 180: break; ! 181: ! 182: case 'v': /* -v Echo hist expanded input */ ! 183: nverbose = 1; /* ... later */ ! 184: break; ! 185: ! 186: case 'x': /* -x Echo just before execution */ ! 187: nexececho = 1; /* ... later */ ! 188: break; ! 189: ! 190: case 'V': /* -V Echo hist expanded input */ ! 191: setNS("verbose"); /* NOW! */ ! 192: break; ! 193: ! 194: case 'X': /* -X Echo just before execution */ ! 195: setNS("echo"); /* NOW! */ ! 196: break; ! 197: ! 198: } while (*cp); ! 199: v++, c--; ! 200: } ! 201: ! 202: if (quitit) /* With all due haste, for debugging */ ! 203: (void) signal(SIGQUIT, SIG_DFL); ! 204: ! 205: /* ! 206: * Unless prevented by -c, -i, -s, or -t, if there ! 207: * are remaining arguments the first of them is the name ! 208: * of a shell file from which to read commands. ! 209: */ ! 210: if (nofile == 0 && c > 0) { ! 211: nofile = open(v[0], 0); ! 212: if (nofile < 0) { ! 213: child++; /* So this ... */ ! 214: Perror(v[0]); /* ... doesn't return */ ! 215: } ! 216: file = v[0]; ! 217: SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */ ! 218: (void) ioctl(SHIN, FIOCLEX, (char *)0); ! 219: prompt = 0; ! 220: c--, v++; ! 221: } ! 222: if (!batch && (uid != geteuid() || getgid() != getegid())) { ! 223: errno = EACCES; ! 224: child++; /* So this ... */ ! 225: Perror("csh"); /* ... doesn't return */ ! 226: } ! 227: /* ! 228: * Consider input a tty if it really is or we are interactive. ! 229: */ ! 230: intty = intact || isatty(SHIN); ! 231: /* ! 232: * Decide whether we should play with signals or not. ! 233: * If we are explicitly told (via -i, or -) or we are a login ! 234: * shell (arg0 starts with -) or the input and output are both ! 235: * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") ! 236: * Note that in only the login shell is it likely that parent ! 237: * may have set signals to be ignored ! 238: */ ! 239: if (loginsh || intact || intty && isatty(SHOUT)) ! 240: setintr = 1; ! 241: #ifdef TELL ! 242: settell(); ! 243: #endif ! 244: /* ! 245: * Save the remaining arguments in argv. ! 246: */ ! 247: setq("argv", v, &shvhed); ! 248: ! 249: /* ! 250: * Set up the prompt. ! 251: */ ! 252: if (prompt) ! 253: set("prompt", uid == 0 ? "# " : "% "); ! 254: ! 255: /* ! 256: * If we are an interactive shell, then start fiddling ! 257: * with the signals; this is a tricky game. ! 258: */ ! 259: shpgrp = getpgrp(0); ! 260: opgrp = tpgrp = -1; ! 261: if (setintr) { ! 262: **av = '-'; ! 263: if (!quitit) /* Wary! */ ! 264: (void) signal(SIGQUIT, SIG_IGN); ! 265: (void) signal(SIGINT, pintr); ! 266: (void) sigblock(sigmask(SIGINT)); ! 267: (void) signal(SIGTERM, SIG_IGN); ! 268: if (quitit == 0 && arginp == 0) { ! 269: (void) signal(SIGTSTP, SIG_IGN); ! 270: (void) signal(SIGTTIN, SIG_IGN); ! 271: (void) signal(SIGTTOU, SIG_IGN); ! 272: /* ! 273: * Wait till in foreground, in case someone ! 274: * stupidly runs ! 275: * csh & ! 276: * dont want to try to grab away the tty. ! 277: */ ! 278: if (isatty(FSHDIAG)) ! 279: f = FSHDIAG; ! 280: else if (isatty(FSHOUT)) ! 281: f = FSHOUT; ! 282: else if (isatty(OLDSTD)) ! 283: f = OLDSTD; ! 284: else ! 285: f = -1; ! 286: retry: ! 287: if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 && ! 288: tpgrp != -1) { ! 289: int ldisc; ! 290: if (tpgrp != shpgrp) { ! 291: sig_t old = signal(SIGTTIN, SIG_DFL); ! 292: (void) kill(0, SIGTTIN); ! 293: (void) signal(SIGTTIN, old); ! 294: goto retry; ! 295: } ! 296: opgrp = shpgrp; ! 297: shpgrp = getpid(); ! 298: tpgrp = shpgrp; ! 299: (void) setpgrp(0, shpgrp); ! 300: (void) ioctl(f, TIOCSPGRP, (char *)&shpgrp); ! 301: (void) ioctl(dcopy(f, FSHTTY), FIOCLEX, ! 302: (char *)0); ! 303: } else { ! 304: notty: ! 305: printf("Warning: no access to tty; thus no job control in this shell...\n"); ! 306: tpgrp = -1; ! 307: } ! 308: } ! 309: } ! 310: if (setintr == 0 && parintr == SIG_DFL) ! 311: setintr++; ! 312: (void) signal(SIGCHLD, pchild); /* while signals not ready */ ! 313: ! 314: /* ! 315: * Set an exit here in case of an interrupt or error reading ! 316: * the shell start-up scripts. ! 317: */ ! 318: setexit(); ! 319: haderr = 0; /* In case second time through */ ! 320: if (!fast && reenter == 0) { ! 321: reenter++; ! 322: { ! 323: int osetintr, omask; ! 324: osetintr = setintr; ! 325: omask = sigblock(sigmask(SIGINT)); ! 326: setintr = 0; ! 327: srcunit(open(_PATH_DOTCSHRC, O_RDONLY), 0, 0); ! 328: if (!fast && !arginp && !onelflg) ! 329: dohash(); ! 330: if (loginsh) ! 331: srcunit(open(_PATH_DOTLOGIN, O_RDONLY), 0, 0); ! 332: (void)sigsetmask(omask); ! 333: setintr = osetintr; ! 334: } ! 335: /* Will have value("home") here because set fast if don't */ ! 336: srccat(value("home"), "/.cshrc"); ! 337: if (!fast && !arginp && !onelflg && !havhash) ! 338: dohash(); ! 339: if (loginsh) { ! 340: srccat(value("home"), "/.login"); ! 341: } ! 342: dosource(loadhist); ! 343: } ! 344: ! 345: /* ! 346: * Now are ready for the -v and -x flags ! 347: */ ! 348: if (nverbose) ! 349: setNS("verbose"); ! 350: if (nexececho) ! 351: setNS("echo"); ! 352: ! 353: /* ! 354: * All the rest of the world is inside this call. ! 355: * The argument to process indicates whether it should ! 356: * catch "error unwinds". Thus if we are a interactive shell ! 357: * our call here will never return by being blown past on an error. ! 358: */ ! 359: process(setintr); ! 360: ! 361: /* ! 362: * Mop-up. ! 363: */ ! 364: if (loginsh) { ! 365: printf("logout\n"); ! 366: (void) close(SHIN); ! 367: child++; ! 368: goodbye(); ! 369: } ! 370: rechist(); ! 371: exitstat(); ! 372: } ! 373: ! 374: untty() ! 375: { ! 376: ! 377: if (tpgrp > 0) { ! 378: (void) setpgrp(0, opgrp); ! 379: (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&opgrp); ! 380: } ! 381: } ! 382: ! 383: importpath(cp) ! 384: char *cp; ! 385: { ! 386: register int i = 0; ! 387: register char *dp; ! 388: register char **pv; ! 389: int c; ! 390: static char dot[2] = {'.', 0}; ! 391: ! 392: for (dp = cp; *dp; dp++) ! 393: if (*dp == ':') ! 394: i++; ! 395: /* ! 396: * i+2 where i is the number of colons in the path. ! 397: * There are i+1 directories in the path plus we need ! 398: * room for a zero terminator. ! 399: */ ! 400: pv = (char **) calloc((unsigned) (i + 2), sizeof (char **)); ! 401: dp = cp; ! 402: i = 0; ! 403: if (*dp) ! 404: for (;;) { ! 405: if ((c = *dp) == ':' || c == 0) { ! 406: *dp = 0; ! 407: pv[i++] = savestr(*cp ? cp : dot); ! 408: if (c) { ! 409: cp = dp + 1; ! 410: *dp = ':'; ! 411: } else ! 412: break; ! 413: } ! 414: dp++; ! 415: } ! 416: pv[i] = 0; ! 417: set1("path", pv, &shvhed); ! 418: } ! 419: ! 420: /* ! 421: * Source to the file which is the catenation of the argument names. ! 422: */ ! 423: srccat(cp, dp) ! 424: char *cp, *dp; ! 425: { ! 426: register char *ep = strspl(cp, dp); ! 427: register int unit = dmove(open(ep, 0), -1); ! 428: ! 429: (void) ioctl(unit, FIOCLEX, (char *)0); ! 430: xfree(ep); ! 431: srcunit(unit, mflag ? 0 : 1, 0); ! 432: } ! 433: ! 434: /* ! 435: * Source to a unit. ! 436: * This occurs on ".cshrc"s and the like. ! 437: */ ! 438: int insource; ! 439: static ! 440: srcunit(unit, onlyown, hflg) ! 441: register int unit; ! 442: bool onlyown, 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: srcunit(open(_PATH_DOTLOGOUT, O_RDONLY), 0, 0); ! 587: if (adrof("home")) ! 588: srccat(value("home"), "/.logout"); ! 589: } ! 590: rechist(); ! 591: exitstat(); ! 592: } ! 593: ! 594: exitstat() ! 595: { ! 596: ! 597: #ifdef PROF ! 598: monitor(0); ! 599: #endif ! 600: /* ! 601: * Note that if STATUS is corrupted (i.e. getn bombs) ! 602: * then error will exit directly because we poke child here. ! 603: * Otherwise we might continue unwarrantedly (sic). ! 604: */ ! 605: child++; ! 606: exit(getn(value("status"))); ! 607: } ! 608: ! 609: /* ! 610: * in the event of a HUP we want to save the history ! 611: */ ! 612: phup() ! 613: { ! 614: rechist(); ! 615: exit(1); ! 616: } ! 617: ! 618: char *jobargv[2] = { "jobs", 0 }; ! 619: /* ! 620: * Catch an interrupt, e.g. during lexical input. ! 621: * If we are an interactive shell, we reset the interrupt catch ! 622: * immediately. In any case we drain the shell output, ! 623: * and finally go through the normal error mechanism, which ! 624: * gets a chance to make the shell go away. ! 625: */ ! 626: pintr() ! 627: { ! 628: pintr1(1); ! 629: } ! 630: ! 631: pintr1(wantnl) ! 632: bool wantnl; ! 633: { ! 634: register char **v; ! 635: long omask; ! 636: ! 637: omask = sigblock(0L); ! 638: if (setintr) { ! 639: (void) sigsetmask(omask & ~sigmask(SIGINT)); ! 640: if (pjobs) { ! 641: pjobs = 0; ! 642: printf("\n"); ! 643: dojobs(jobargv); ! 644: bferr("Interrupted"); ! 645: } ! 646: } ! 647: (void) sigsetmask(omask & ~sigmask(SIGCHLD)); ! 648: draino(); ! 649: ! 650: /* ! 651: * If we have an active "onintr" then we search for the label. ! 652: * Note that if one does "onintr -" then we shan't be interruptible ! 653: * so we needn't worry about that here. ! 654: */ ! 655: if (gointr) { ! 656: search(ZGOTO, 0, gointr); ! 657: timflg = 0; ! 658: if (v = pargv) ! 659: pargv = 0, blkfree(v); ! 660: if (v = gargv) ! 661: gargv = 0, blkfree(v); ! 662: reset(); ! 663: } else if (intty && wantnl) ! 664: printf("\n"); /* Some like this, others don't */ ! 665: error(NOSTR); ! 666: } ! 667: ! 668: /* ! 669: * Process is the main driving routine for the shell. ! 670: * It runs all command processing, except for those within { ... } ! 671: * in expressions (which is run by a routine evalav in sh.exp.c which ! 672: * is a stripped down process), and `...` evaluation which is run ! 673: * also by a subset of this code in sh.glob.c in the routine backeval. ! 674: * ! 675: * The code here is a little strange because part of it is interruptible ! 676: * and hence freeing of structures appears to occur when none is necessary ! 677: * if this is ignored. ! 678: * ! 679: * Note that if catch is not set then we will unwind on any error. ! 680: * If an end-of-file occurs, we return. ! 681: */ ! 682: process(catch) ! 683: bool catch; ! 684: { ! 685: jmp_buf osetexit; ! 686: register struct command *t; ! 687: ! 688: getexit(osetexit); ! 689: for (;;) { ! 690: pendjob(); ! 691: paraml.next = paraml.prev = ¶ml; ! 692: paraml.word = ""; ! 693: t = 0; ! 694: setexit(); ! 695: justpr = enterhist; /* execute if not entering history */ ! 696: ! 697: /* ! 698: * Interruptible during interactive reads ! 699: */ ! 700: if (setintr) ! 701: (void) sigsetmask(sigblock(0L) & ~sigmask(SIGINT)); ! 702: ! 703: /* ! 704: * For the sake of reset() ! 705: */ ! 706: freelex(¶ml), freesyn(t), t = 0; ! 707: ! 708: if (haderr) { ! 709: if (!catch) { ! 710: /* unwind */ ! 711: doneinp = 0; ! 712: resexit(osetexit); ! 713: reset(); ! 714: } ! 715: haderr = 0; ! 716: /* ! 717: * Every error is eventually caught here or ! 718: * the shell dies. It is at this ! 719: * point that we clean up any left-over open ! 720: * files, by closing all but a fixed number ! 721: * of pre-defined files. Thus routines don't ! 722: * have to worry about leaving files open due ! 723: * to deeper errors... they will get closed here. ! 724: */ ! 725: closem(); ! 726: continue; ! 727: } ! 728: if (doneinp) { ! 729: doneinp = 0; ! 730: break; ! 731: } ! 732: if (chkstop) ! 733: chkstop--; ! 734: if (neednote) ! 735: pnote(); ! 736: if (intty && prompt && evalvec == 0) { ! 737: mailchk(); ! 738: /* ! 739: * If we are at the end of the input buffer ! 740: * then we are going to read fresh stuff. ! 741: * Otherwise, we are rereading input and don't ! 742: * need or want to prompt. ! 743: */ ! 744: if (fseekp == feobp) ! 745: printprompt(); ! 746: } ! 747: err = 0; ! 748: ! 749: /* ! 750: * Echo not only on VERBOSE, but also with history expansion. ! 751: * If there is a lexical error then we forego history echo. ! 752: */ ! 753: if (lex(¶ml) && !err && intty || ! 754: adrof("verbose")) { ! 755: haderr = 1; ! 756: prlex(¶ml); ! 757: haderr = 0; ! 758: } ! 759: ! 760: /* ! 761: * The parser may lose space if interrupted. ! 762: */ ! 763: if (setintr) ! 764: (void) sigblock(sigmask(SIGINT)); ! 765: ! 766: /* ! 767: * Save input text on the history list if ! 768: * reading in old history, or it ! 769: * is from the terminal at the top level and not ! 770: * in a loop. ! 771: */ ! 772: if (enterhist || catch && intty && !whyles) ! 773: savehist(¶ml); ! 774: ! 775: /* ! 776: * Print lexical error messages, except when sourcing ! 777: * history lists. ! 778: */ ! 779: if (!enterhist && err) ! 780: error(err); ! 781: ! 782: /* ! 783: * If had a history command :p modifier then ! 784: * this is as far as we should go ! 785: */ ! 786: if (justpr) ! 787: reset(); ! 788: ! 789: alias(¶ml); ! 790: ! 791: /* ! 792: * Parse the words of the input into a parse tree. ! 793: */ ! 794: t = syntax(paraml.next, ¶ml, 0); ! 795: if (err) ! 796: error(err); ! 797: ! 798: /* ! 799: * Execute the parse tree ! 800: */ ! 801: execute(t, tpgrp); ! 802: ! 803: /* ! 804: * Made it! ! 805: */ ! 806: freelex(¶ml), freesyn(t); ! 807: } ! 808: resexit(osetexit); ! 809: } ! 810: ! 811: dosource(t) ! 812: register char **t; ! 813: { ! 814: register char *f; ! 815: register int u; ! 816: bool hflg = 0; ! 817: char buf[BUFSIZ]; ! 818: ! 819: t++; ! 820: if (*t && eq(*t, "-h")) { ! 821: t++; ! 822: hflg++; ! 823: } ! 824: (void) strcpy(buf, *t); ! 825: f = globone(buf); ! 826: u = dmove(open(f, 0), -1); ! 827: xfree(f); ! 828: if (u < 0 && !hflg) ! 829: Perror(f); ! 830: (void) ioctl(u, FIOCLEX, (char *)0); ! 831: srcunit(u, 0, hflg); ! 832: } ! 833: ! 834: /* ! 835: * Check for mail. ! 836: * If we are a login shell, then we don't want to tell ! 837: * about any mail file unless its been modified ! 838: * after the time we started. ! 839: * This prevents us from telling the user things he already ! 840: * knows, since the login program insists on saying ! 841: * "You have mail." ! 842: */ ! 843: mailchk() ! 844: { ! 845: register struct varent *v; ! 846: register char **vp; ! 847: time_t t; ! 848: int intvl, cnt; ! 849: struct stat stb; ! 850: bool new; ! 851: ! 852: v = adrof("mail"); ! 853: if (v == 0) ! 854: return; ! 855: (void) time(&t); ! 856: vp = v->vec; ! 857: cnt = blklen(vp); ! 858: intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; ! 859: if (intvl < 1) ! 860: intvl = 1; ! 861: if (chktim + intvl > t) ! 862: return; ! 863: for (; *vp; vp++) { ! 864: if (stat(*vp, &stb) < 0) ! 865: continue; ! 866: new = stb.st_mtime > time0.tv_sec; ! 867: if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || ! 868: (stb.st_atime < chktim && stb.st_mtime < chktim) || ! 869: loginsh && !new) ! 870: continue; ! 871: if (cnt == 1) ! 872: printf("You have %smail.\n", new ? "new " : ""); ! 873: else ! 874: printf("%s in %s.\n", new ? "New mail" : "Mail", *vp); ! 875: } ! 876: chktim = t; ! 877: } ! 878: ! 879: #include <pwd.h> ! 880: /* ! 881: * Extract a home directory from the password file ! 882: * The argument points to a buffer where the name of the ! 883: * user whose home directory is sought is currently. ! 884: * We write the home directory of the user back there. ! 885: */ ! 886: gethdir(home) ! 887: char *home; ! 888: { ! 889: register struct passwd *pp = getpwnam(home); ! 890: ! 891: if (pp == 0) ! 892: return (1); ! 893: (void) strcpy(home, pp->pw_dir); ! 894: return (0); ! 895: } ! 896: ! 897: /* ! 898: * Move the initial descriptors to their eventual ! 899: * resting places, closin all other units. ! 900: */ ! 901: initdesc() ! 902: { ! 903: ! 904: didfds = 0; /* 0, 1, 2 aren't set up */ ! 905: (void) ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, (char *)0); ! 906: (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, (char *)0); ! 907: (void) ioctl(SHDIAG = dcopy(2, FSHDIAG), FIOCLEX, (char *)0); ! 908: (void) ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, (char *)0); ! 909: closem(); ! 910: } ! 911: ! 912: #ifdef PROF ! 913: done(i) ! 914: #else ! 915: exit(i) ! 916: #endif ! 917: int i; ! 918: { ! 919: ! 920: untty(); ! 921: _exit(i); ! 922: } ! 923: ! 924: printprompt() ! 925: { ! 926: register char *cp; ! 927: ! 928: if (!whyles) { ! 929: for (cp = value("prompt"); *cp; cp++) ! 930: if (*cp == HIST) ! 931: printf("%d", eventno + 1); ! 932: else { ! 933: if (*cp == '\\' && cp[1] == HIST) ! 934: cp++; ! 935: cshputchar(*cp | QUOTE); ! 936: } ! 937: } else ! 938: /* ! 939: * Prompt for forward reading loop ! 940: * body content. ! 941: */ ! 942: printf("? "); ! 943: flush(); ! 944: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.