|
|
1.1 ! root 1: static char *sccsid = "@(#)sh.c 4.12 6/11/83"; ! 2: ! 3: #include "sh.h" ! 4: #include <sys/ioctl.h> ! 5: /* ! 6: * C Shell ! 7: * ! 8: * Bill Joy, UC Berkeley, California, USA ! 9: * October 1978, May 1980 ! 10: * ! 11: * Jim Kulp, IIASA, Laxenburg, Austria ! 12: * April 1980 ! 13: */ ! 14: ! 15: char *pathlist[] = { ".", "/usr/ucb", "/bin", "/usr/bin", 0 }; ! 16: char *dumphist[] = { "history", "-h", 0, 0 }; ! 17: char *loadhist[] = { "source", "-h", "~/.history", 0 }; ! 18: char HIST = '!'; ! 19: char HISTSUB = '^'; ! 20: bool nofile; ! 21: bool reenter; ! 22: bool nverbose; ! 23: bool nexececho; ! 24: bool quitit; ! 25: bool fast; ! 26: bool prompt = 1; ! 27: bool enterhist = 0; ! 28: ! 29: main(c, av) ! 30: int c; ! 31: char **av; ! 32: { ! 33: register char **v, *cp; ! 34: register int f; ! 35: ! 36: settimes(); /* Immed. estab. timing base */ ! 37: v = av; ! 38: if (eq(v[0], "a.out")) /* A.out's are quittable */ ! 39: quitit = 1; ! 40: uid = getuid(); ! 41: loginsh = **v == '-'; ! 42: if (loginsh) ! 43: time(&chktim); ! 44: ! 45: /* ! 46: * Move the descriptors to safe places. ! 47: * The variable didfds is 0 while we have only FSH* to work with. ! 48: * When didfds is true, we have 0,1,2 and prefer to use these. ! 49: */ ! 50: initdesc(); ! 51: ! 52: /* ! 53: * Initialize the shell variables. ! 54: * ARGV and PROMPT are initialized later. ! 55: * STATUS is also munged in several places. ! 56: * CHILD is munged when forking/waiting ! 57: */ ! 58: ! 59: set("status", "0"); ! 60: dinit(cp = getenv("HOME")); /* dinit thinks that HOME == cwd in a ! 61: * login shell */ ! 62: if (cp == NOSTR) ! 63: fast++; /* No home -> can't read scripts */ ! 64: else ! 65: set("home", savestr(cp)); ! 66: /* ! 67: * Grab other useful things from the environment. ! 68: * Should we grab everything?? ! 69: */ ! 70: if ((cp = getenv("USER")) != NOSTR) ! 71: set("user", savestr(cp)); ! 72: if ((cp = getenv("TERM")) != NOSTR) ! 73: set("term", savestr(cp)); ! 74: /* ! 75: * Re-initialize path if set in environment ! 76: */ ! 77: if ((cp = getenv("PATH")) == NOSTR) ! 78: set1("path", saveblk(pathlist), &shvhed); ! 79: else { ! 80: register unsigned i = 0; ! 81: register char *dp; ! 82: register char **pv; ! 83: ! 84: for (dp = cp; *dp; dp++) ! 85: if (*dp == ':') ! 86: i++; ! 87: pv = (char **)calloc(i+2, sizeof (char **)); ! 88: for (dp = cp, i = 0; ;) ! 89: if (*dp == ':') { ! 90: *dp = 0; ! 91: pv[i++] = savestr(*cp ? cp : "."); ! 92: *dp++ = ':'; ! 93: cp = dp; ! 94: } else if (*dp++ == 0) { ! 95: pv[i++] = savestr(*cp ? cp : "."); ! 96: break; ! 97: } ! 98: pv[i] = 0; ! 99: set1("path", pv, &shvhed); ! 100: } ! 101: set("shell", SHELLPATH); ! 102: ! 103: doldol = putn(getpid()); /* For $$ */ ! 104: shtemp = strspl("/tmp/sh", doldol); /* For << */ ! 105: ! 106: /* ! 107: * Record the interrupt states from the parent process. ! 108: * If the parent is non-interruptible our hand must be forced ! 109: * or we (and our children) won't be either. ! 110: * Our children inherit termination from our parent. ! 111: * We catch it only if we are the login shell. ! 112: */ ! 113: parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */ ! 114: sigset(SIGINT, parintr); /* ... restore */ ! 115: parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */ ! 116: signal(SIGTERM, parterm); /* ... restore */ ! 117: if (loginsh) { ! 118: signal(SIGHUP, phup); /* exit processing on HUP */ ! 119: signal(SIGXCPU, phup); /* ...and on XCPU */ ! 120: signal(SIGXFSZ, phup); /* ...and on XFSZ */ ! 121: } ! 122: ! 123: /* ! 124: * Process the arguments. ! 125: * ! 126: * Note that processing of -v/-x is actually delayed till after ! 127: * script processing. ! 128: * ! 129: * We set the first character of our name to be '-' if we are ! 130: * a shell running interruptible commands. Many programs which ! 131: * examine ps'es use this to filter such shells out. ! 132: */ ! 133: c--, v++; ! 134: while (c > 0 && (cp = v[0])[0] == '-') { ! 135: do switch (*cp++) { ! 136: ! 137: case 0: /* - Interruptible, no prompt */ ! 138: prompt = 0; ! 139: setintr++; ! 140: nofile++; ! 141: break; ! 142: ! 143: case 'c': /* -c Command input from arg */ ! 144: if (c == 1) ! 145: exit(0); ! 146: c--, v++; ! 147: arginp = v[0]; ! 148: prompt = 0; ! 149: nofile++; ! 150: break; ! 151: ! 152: case 'e': /* -e Exit on any error */ ! 153: exiterr++; ! 154: break; ! 155: ! 156: case 'f': /* -f Fast start */ ! 157: fast++; ! 158: break; ! 159: ! 160: case 'i': /* -i Interactive, even if !intty */ ! 161: intact++; ! 162: nofile++; ! 163: break; ! 164: ! 165: case 'n': /* -n Don't execute */ ! 166: noexec++; ! 167: break; ! 168: ! 169: case 'q': /* -q (Undoc'd) ... die on quit */ ! 170: quitit = 1; ! 171: break; ! 172: ! 173: case 's': /* -s Read from std input */ ! 174: nofile++; ! 175: break; ! 176: ! 177: case 't': /* -t Read one line from input */ ! 178: onelflg = 2; ! 179: prompt = 0; ! 180: nofile++; ! 181: break; ! 182: ! 183: case 'v': /* -v Echo hist expanded input */ ! 184: nverbose = 1; /* ... later */ ! 185: break; ! 186: ! 187: case 'x': /* -x Echo just before execution */ ! 188: nexececho = 1; /* ... later */ ! 189: break; ! 190: ! 191: case 'V': /* -V Echo hist expanded input */ ! 192: setNS("verbose"); /* NOW! */ ! 193: break; ! 194: ! 195: case 'X': /* -X Echo just before execution */ ! 196: setNS("echo"); /* NOW! */ ! 197: break; ! 198: ! 199: } while (*cp); ! 200: v++, c--; ! 201: } ! 202: ! 203: if (quitit) /* With all due haste, for debugging */ ! 204: signal(SIGQUIT, SIG_DFL); ! 205: ! 206: /* ! 207: * Unless prevented by -, -c, -i, -s, or -t, if there ! 208: * are remaining arguments the first of them is the name ! 209: * of a shell file from which to read commands. ! 210: */ ! 211: if (nofile == 0 && c > 0) { ! 212: nofile = open(v[0], 0); ! 213: if (nofile < 0) { ! 214: child++; /* So this ... */ ! 215: Perror(v[0]); /* ... doesn't return */ ! 216: } ! 217: file = v[0]; ! 218: SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */ ! 219: prompt = 0; ! 220: c--, v++; ! 221: } ! 222: /* ! 223: * Consider input a tty if it really is or we are interactive. ! 224: */ ! 225: intty = intact || isatty(SHIN); ! 226: /* ! 227: * Decide whether we should play with signals or not. ! 228: * If we are explicitly told (via -i, or -) or we are a login ! 229: * shell (arg0 starts with -) or the input and output are both ! 230: * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") ! 231: * Note that in only the login shell is it likely that parent ! 232: * may have set signals to be ignored ! 233: */ ! 234: if (loginsh || intact || intty && isatty(SHOUT)) ! 235: setintr = 1; ! 236: #ifdef TELL ! 237: settell(); ! 238: #endif ! 239: /* ! 240: * Save the remaining arguments in argv. ! 241: */ ! 242: setq("argv", v, &shvhed); ! 243: ! 244: /* ! 245: * Set up the prompt. ! 246: */ ! 247: if (prompt) ! 248: set("prompt", uid == 0 ? "# " : "% "); ! 249: ! 250: /* ! 251: * If we are an interactive shell, then start fiddling ! 252: * with the signals; this is a tricky game. ! 253: */ ! 254: shpgrp = getpgrp(0); ! 255: opgrp = tpgrp = -1; ! 256: oldisc = -1; ! 257: if (setintr) { ! 258: **av = '-'; ! 259: if (!quitit) /* Wary! */ ! 260: signal(SIGQUIT, SIG_IGN); ! 261: sigset(SIGINT, pintr); ! 262: sighold(SIGINT); ! 263: signal(SIGTERM, SIG_IGN); ! 264: if (quitit == 0 && arginp == 0) { ! 265: signal(SIGTSTP, SIG_IGN); ! 266: signal(SIGTTIN, SIG_IGN); ! 267: signal(SIGTTOU, SIG_IGN); ! 268: /* ! 269: * Wait till in foreground, in case someone ! 270: * stupidly runs ! 271: * csh & ! 272: * dont want to try to grab away the tty. ! 273: */ ! 274: if (isatty(FSHDIAG)) ! 275: f = FSHDIAG; ! 276: else if (isatty(FSHOUT)) ! 277: f = FSHOUT; ! 278: else if (isatty(OLDSTD)) ! 279: f = OLDSTD; ! 280: else ! 281: f = -1; ! 282: retry: ! 283: if (ioctl(f, TIOCGPGRP, &tpgrp) == 0 && tpgrp != -1) { ! 284: int ldisc; ! 285: if (tpgrp != shpgrp) { ! 286: int (*old)() = sigsys(SIGTTIN, SIG_DFL); ! 287: kill(0, SIGTTIN); ! 288: sigsys(SIGTTIN, old); ! 289: goto retry; ! 290: } ! 291: if (ioctl(f, TIOCGETD, &oldisc) != 0) ! 292: goto notty; ! 293: if (oldisc != NTTYDISC) { ! 294: #ifdef DEBUG ! 295: printf("Switching to new tty driver...\n"); ! 296: #endif DEBUG ! 297: ldisc = NTTYDISC; ! 298: ioctl(f, TIOCSETD, &ldisc); ! 299: } else ! 300: oldisc = -1; ! 301: opgrp = shpgrp; ! 302: shpgrp = getpid(); ! 303: tpgrp = shpgrp; ! 304: ioctl(f, TIOCSPGRP, &shpgrp); ! 305: setpgrp(0, shpgrp); ! 306: dcopy(f, FSHTTY); ! 307: ioctl(FSHTTY, FIOCLEX, 0); ! 308: } else { ! 309: notty: ! 310: printf("Warning: no access to tty; thus no job control in this shell...\n"); ! 311: tpgrp = -1; ! 312: } ! 313: } ! 314: } ! 315: if (setintr == 0 && parintr == SIG_DFL) ! 316: setintr++; ! 317: sigset(SIGCHLD, pchild); /* while signals not ready */ ! 318: ! 319: /* ! 320: * Set an exit here in case of an interrupt or error reading ! 321: * the shell start-up scripts. ! 322: */ ! 323: setexit(); ! 324: haderr = 0; /* In case second time through */ ! 325: if (!fast && reenter == 0) { ! 326: reenter++; ! 327: /* Will have value("home") here because set fast if don't */ ! 328: srccat(value("home"), "/.cshrc"); ! 329: if (!fast && !arginp && !onelflg) ! 330: dohash(); ! 331: dosource(loadhist); ! 332: if (loginsh) { ! 333: srccat(value("home"), "/.login"); ! 334: } ! 335: } ! 336: ! 337: /* ! 338: * Now are ready for the -v and -x flags ! 339: */ ! 340: if (nverbose) ! 341: setNS("verbose"); ! 342: if (nexececho) ! 343: setNS("echo"); ! 344: ! 345: /* ! 346: * All the rest of the world is inside this call. ! 347: * The argument to process indicates whether it should ! 348: * catch "error unwinds". Thus if we are a interactive shell ! 349: * our call here will never return by being blown past on an error. ! 350: */ ! 351: process(setintr); ! 352: ! 353: /* ! 354: * Mop-up. ! 355: */ ! 356: if (loginsh) { ! 357: printf("logout\n"); ! 358: close(SHIN); ! 359: child++; ! 360: goodbye(); ! 361: } ! 362: rechist(); ! 363: exitstat(); ! 364: } ! 365: ! 366: untty() ! 367: { ! 368: ! 369: if (tpgrp > 0) { ! 370: setpgrp(0, opgrp); ! 371: ioctl(FSHTTY, TIOCSPGRP, &opgrp); ! 372: if (oldisc != -1 && oldisc != NTTYDISC) { ! 373: #ifdef DEBUG ! 374: printf("\nReverting to old tty driver...\n"); ! 375: #endif DEBUG ! 376: ioctl(FSHTTY, TIOCSETD, &oldisc); ! 377: } ! 378: } ! 379: } ! 380: ! 381: importpath(cp) ! 382: char *cp; ! 383: { ! 384: register int i = 0; ! 385: register char *dp; ! 386: register char **pv; ! 387: int c; ! 388: static char dot[2] = {'.', 0}; ! 389: ! 390: for (dp = cp; *dp; dp++) ! 391: if (*dp == ':') ! 392: i++; ! 393: /* ! 394: * i+2 where i is the number of colons in the path. ! 395: * There are i+1 directories in the path plus we need ! 396: * room for a zero terminator. ! 397: */ ! 398: pv = (char **) calloc(i+2, sizeof (char **)); ! 399: dp = cp; ! 400: i = 0; ! 401: if (*dp) ! 402: for (;;) { ! 403: if ((c = *dp) == ':' || c == 0) { ! 404: *dp = 0; ! 405: pv[i++] = savestr(*cp ? cp : dot); ! 406: if (c) { ! 407: cp = dp + 1; ! 408: *dp = ':'; ! 409: } else ! 410: break; ! 411: } ! 412: dp++; ! 413: } ! 414: pv[i] = 0; ! 415: set1("path", pv, &shvhed); ! 416: } ! 417: ! 418: /* ! 419: * Source to the file which is the catenation of the argument names. ! 420: */ ! 421: srccat(cp, dp) ! 422: char *cp, *dp; ! 423: { ! 424: register char *ep = strspl(cp, dp); ! 425: register int unit = dmove(open(ep, 0), -1); ! 426: ! 427: /* ioctl(unit, FIOCLEX, NULL); */ ! 428: xfree(ep); ! 429: #ifdef INGRES ! 430: srcunit(unit, 0, 0); ! 431: #else ! 432: srcunit(unit, 1, 0); ! 433: #endif ! 434: } ! 435: ! 436: /* ! 437: * Source to a unit. If onlyown it must be our file or our group or ! 438: * we don't chance it. This occurs on ".cshrc"s and the like. ! 439: */ ! 440: srcunit(unit, onlyown, hflg) ! 441: register int unit; ! 442: bool onlyown; ! 443: bool hflg; ! 444: { ! 445: /* We have to push down a lot of state here */ ! 446: /* All this could go into a structure */ ! 447: int oSHIN = -1, oldintty = intty; ! 448: struct whyle *oldwhyl = whyles; ! 449: char *ogointr = gointr, *oarginp = arginp; ! 450: char *oevalp = evalp, **oevalvec = evalvec; ! 451: int oonelflg = onelflg; ! 452: bool oenterhist = enterhist; ! 453: char OHIST = HIST; ! 454: #ifdef TELL ! 455: bool otell = cantell; ! 456: #endif ! 457: struct Bin saveB; ! 458: ! 459: /* The (few) real local variables */ ! 460: jmp_buf oldexit; ! 461: int reenter; ! 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: 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: getexit(oldexit); ! 489: reenter = 0; ! 490: if (setintr) ! 491: sighold(SIGINT); ! 492: setexit(); ! 493: reenter++; ! 494: if (reenter == 1) { ! 495: /* Setup the new values of the state stuff saved above */ ! 496: copy((char *)&saveB, (char *)&B, sizeof saveB); ! 497: fbuf = (char **) 0; ! 498: fseekp = feobp = fblocks = 0; ! 499: oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; ! 500: intty = isatty(SHIN), whyles = 0, gointr = 0; ! 501: evalvec = 0; evalp = 0; ! 502: enterhist = hflg; ! 503: if (enterhist) ! 504: HIST = '\0'; ! 505: /* ! 506: * Now if we are allowing commands to be interrupted, ! 507: * we let ourselves be interrupted. ! 508: */ ! 509: if (setintr) ! 510: sigrelse(SIGINT); ! 511: #ifdef TELL ! 512: settell(); ! 513: #endif ! 514: process(0); /* 0 -> blow away on errors */ ! 515: } ! 516: if (setintr) ! 517: sigrelse(SIGINT); ! 518: if (oSHIN >= 0) { ! 519: register int i; ! 520: ! 521: /* We made it to the new state... free up its storage */ ! 522: /* This code could get run twice but xfree doesn't care */ ! 523: for (i = 0; i < fblocks; i++) ! 524: xfree(fbuf[i]); ! 525: xfree((char *)fbuf); ! 526: ! 527: /* Reset input arena */ ! 528: copy((char *)&B, (char *)&saveB, sizeof B); ! 529: ! 530: close(SHIN), SHIN = oSHIN; ! 531: arginp = oarginp, onelflg = oonelflg; ! 532: evalp = oevalp, evalvec = oevalvec; ! 533: intty = oldintty, whyles = oldwhyl, gointr = ogointr; ! 534: if (enterhist) ! 535: HIST = OHIST; ! 536: enterhist = oenterhist; ! 537: #ifdef TELL ! 538: cantell = otell; ! 539: #endif ! 540: } ! 541: ! 542: resexit(oldexit); ! 543: /* ! 544: * If process reset() (effectively an unwind) then ! 545: * we must also unwind. ! 546: */ ! 547: if (reenter >= 2) ! 548: error(NOSTR); ! 549: } ! 550: ! 551: rechist() ! 552: { ! 553: char buf[BUFSIZ]; ! 554: int fp, ftmp, oldidfds; ! 555: ! 556: if (!fast) { ! 557: if (value("savehist")[0] == '\0') ! 558: return; ! 559: strcpy(buf, value("home")); ! 560: strcat(buf, "/.history"); ! 561: fp = creat(buf, 0777); ! 562: if (fp == -1) ! 563: return; ! 564: oldidfds = didfds; ! 565: didfds = 0; ! 566: ftmp = SHOUT; ! 567: SHOUT = fp; ! 568: strcpy(buf, value("savehist")); ! 569: dumphist[2] = buf; ! 570: dohist(dumphist); ! 571: close(fp); ! 572: SHOUT = ftmp; ! 573: didfds = oldidfds; ! 574: } ! 575: } ! 576: ! 577: goodbye() ! 578: { ! 579: if (loginsh) { ! 580: signal(SIGQUIT, SIG_IGN); ! 581: sigset(SIGINT, SIG_IGN); ! 582: signal(SIGTERM, SIG_IGN); ! 583: setintr = 0; /* No interrupts after "logout" */ ! 584: if (adrof("home")) ! 585: srccat(value("home"), "/.logout"); ! 586: } ! 587: rechist(); ! 588: exitstat(); ! 589: } ! 590: ! 591: exitstat() ! 592: { ! 593: ! 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: ! 630: if (setintr) { ! 631: sigrelse(SIGINT); ! 632: if (pjobs) { ! 633: pjobs = 0; ! 634: printf("\n"); ! 635: dojobs(jobargv); ! 636: bferr("Interrupted"); ! 637: } ! 638: } ! 639: if (setintr) ! 640: sighold(SIGINT); ! 641: sigrelse(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: register char *cp; ! 680: jmp_buf osetexit; ! 681: struct command *t; ! 682: ! 683: getexit(osetexit); ! 684: for (;;) { ! 685: pendjob(); ! 686: paraml.next = paraml.prev = ¶ml; ! 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: sigrelse(SIGINT); ! 697: ! 698: /* ! 699: * For the sake of reset() ! 700: */ ! 701: freelex(¶ml), 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 && 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: if (!whyles) ! 741: for (cp = value("prompt"); *cp; cp++) ! 742: if (*cp == HIST) ! 743: printf("%d", eventno + 1); ! 744: else { ! 745: if (*cp == '\\' && cp[1] == HIST) ! 746: cp++; ! 747: putchar(*cp | QUOTE); ! 748: } ! 749: else ! 750: /* ! 751: * Prompt for forward reading loop ! 752: * body content. ! 753: */ ! 754: printf("? "); ! 755: flush(); ! 756: } ! 757: err = 0; ! 758: ! 759: /* ! 760: * Echo not only on VERBOSE, but also with history expansion. ! 761: * If there is a lexical error then we forego history echo. ! 762: */ ! 763: if (lex(¶ml) && !err && intty || ! 764: adrof("verbose")) { ! 765: haderr = 1; ! 766: prlex(¶ml); ! 767: haderr = 0; ! 768: } ! 769: ! 770: /* ! 771: * The parser may lose space if interrupted. ! 772: */ ! 773: if (setintr) ! 774: sighold(SIGINT); ! 775: ! 776: /* ! 777: * Save input text on the history list if ! 778: * reading in old history, or it ! 779: * is from the terminal at the top level and not ! 780: * in a loop. ! 781: */ ! 782: if (enterhist || catch && intty && !whyles) ! 783: savehist(¶ml); ! 784: ! 785: /* ! 786: * Print lexical error messages, except when sourcing ! 787: * history lists. ! 788: */ ! 789: if (!enterhist && err) ! 790: error(err); ! 791: ! 792: /* ! 793: * If had a history command :p modifier then ! 794: * this is as far as we should go ! 795: */ ! 796: if (justpr) ! 797: reset(); ! 798: ! 799: alias(¶ml); ! 800: ! 801: /* ! 802: * Parse the words of the input into a parse tree. ! 803: */ ! 804: t = syntax(paraml.next, ¶ml, 0); ! 805: if (err) ! 806: error(err); ! 807: ! 808: /* ! 809: * Execute the parse tree ! 810: */ ! 811: execute(t, tpgrp); ! 812: ! 813: /* ! 814: * Made it! ! 815: */ ! 816: freelex(¶ml), freesyn(t); ! 817: } ! 818: resexit(osetexit); ! 819: } ! 820: ! 821: dosource(t) ! 822: register char **t; ! 823: { ! 824: register char *f; ! 825: register int u; ! 826: bool hflg = 0; ! 827: char buf[BUFSIZ]; ! 828: ! 829: t++; ! 830: if (*t && eq(*t, "-h")) { ! 831: t++; ! 832: hflg++; ! 833: } ! 834: strcpy(buf, *t); ! 835: f = globone(buf); ! 836: u = dmove(open(f, 0), -1); ! 837: xfree(f); ! 838: if (u < 0 && !hflg) ! 839: Perror(f); ! 840: srcunit(u, 0, hflg); ! 841: } ! 842: ! 843: /* ! 844: * Check for mail. ! 845: * If we are a login shell, then we don't want to tell ! 846: * about any mail file unless its been modified ! 847: * after the time we started. ! 848: * This prevents us from telling the user things he already ! 849: * knows, since the login program insists on saying ! 850: * "You have mail." ! 851: */ ! 852: mailchk() ! 853: { ! 854: register struct varent *v; ! 855: register char **vp; ! 856: time_t t; ! 857: int intvl, cnt; ! 858: struct stat stb; ! 859: bool new; ! 860: ! 861: v = adrof("mail"); ! 862: if (v == 0) ! 863: return; ! 864: time(&t); ! 865: vp = v->vec; ! 866: cnt = blklen(vp); ! 867: intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; ! 868: if (intvl < 1) ! 869: intvl = 1; ! 870: if (chktim + intvl > t) ! 871: return; ! 872: for (; *vp; vp++) { ! 873: if (stat(*vp, &stb) < 0) ! 874: continue; ! 875: new = stb.st_mtime > time0.tv_sec; ! 876: if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || ! 877: (stb.st_atime < chktim && stb.st_mtime < chktim) || ! 878: loginsh && !new) ! 879: continue; ! 880: if (cnt == 1) ! 881: printf("You have %smail.\n", new ? "new " : ""); ! 882: else ! 883: printf("%s in %s.\n", new ? "New mail" : "Mail", *vp); ! 884: } ! 885: chktim = t; ! 886: } ! 887: ! 888: #include <pwd.h> ! 889: /* ! 890: * Extract a home directory from the password file ! 891: * The argument points to a buffer where the name of the ! 892: * user whose home directory is sought is currently. ! 893: * We write the home directory of the user back there. ! 894: */ ! 895: gethdir(home) ! 896: char *home; ! 897: { ! 898: register struct passwd *pp = getpwnam(home); ! 899: ! 900: if (pp == 0) ! 901: return (1); ! 902: strcpy(home, pp->pw_dir); ! 903: return (0); ! 904: } ! 905: ! 906: /* ! 907: * Move the initial descriptors to their eventual ! 908: * resting places, closin all other units. ! 909: */ ! 910: initdesc() ! 911: { ! 912: ! 913: didcch = 0; /* Havent closed for child */ ! 914: didfds = 0; /* 0, 1, 2 aren't set up */ ! 915: SHIN = dcopy(0, FSHIN); ! 916: SHOUT = dcopy(1, FSHOUT); ! 917: SHDIAG = dcopy(2, FSHDIAG); ! 918: OLDSTD = dcopy(SHIN, FOLDSTD); ! 919: closem(); ! 920: } ! 921: ! 922: exit(i) ! 923: int i; ! 924: { ! 925: ! 926: untty(); ! 927: #ifdef PROF ! 928: IEH3exit(i); ! 929: #else ! 930: _exit(i); ! 931: #endif ! 932: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.