|
|
1.1 ! root 1: static char *sccsid = "@(#)sh.c 4.2 3/11/81"; ! 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: extern int ntty_ld, tty_ld; ! 16: ! 17: char *pathlist[] = { ".", "/usr/ucb", "/bin", "/usr/bin", 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: ! 28: main(c, av) ! 29: int c; ! 30: char **av; ! 31: { ! 32: register char **v, *cp; ! 33: register int f; ! 34: ! 35: settimes(); /* Immed. estab. timing base */ ! 36: v = av; ! 37: if (eq(v[0], "a.out")) /* A.out's are quittable */ ! 38: quitit = 1; ! 39: uid = getuid(); ! 40: loginsh = **v == '-'; ! 41: if (loginsh) ! 42: time(&chktim); ! 43: ! 44: /* ! 45: * Move the descriptors to safe places. ! 46: * The variable didfds is 0 while we have only FSH* to work with. ! 47: * When didfds is true, we have 0,1,2 and prefer to use these. ! 48: */ ! 49: initdesc(); ! 50: ! 51: /* ! 52: * Initialize the shell variables. ! 53: * ARGV and PROMPT are initialized later. ! 54: * STATUS is also munged in several places. ! 55: * CHILD is munged when forking/waiting ! 56: */ ! 57: ! 58: set("status", "0"); ! 59: dinit(cp = getenv("HOME")); /* dinit thinks that HOME == cwd in a ! 60: * login shell */ ! 61: if (cp == NOSTR) ! 62: fast++; /* No home -> can't read scripts */ ! 63: else ! 64: set("home", savestr(cp)); ! 65: /* ! 66: * Grab other useful things from the environment. ! 67: * Should we grab everything?? ! 68: */ ! 69: if ((cp = getenv("USER")) != NOSTR) ! 70: set("user", savestr(cp)); ! 71: if ((cp = getenv("TERM")) != NOSTR) ! 72: set("term", savestr(cp)); ! 73: /* ! 74: * Re-initialize path if set in environment ! 75: */ ! 76: if ((cp = getenv("PATH")) == NOSTR) ! 77: set1("path", saveblk(pathlist), &shvhed); ! 78: else { ! 79: register unsigned i = 0; ! 80: register char *dp; ! 81: register char **pv; ! 82: ! 83: for (dp = cp; *dp; dp++) ! 84: if (*dp == ':') ! 85: i++; ! 86: pv = (char **)calloc(i+2, sizeof (char **)); ! 87: for (dp = cp, i = 0; ;) ! 88: if (*dp == ':') { ! 89: *dp = 0; ! 90: pv[i++] = savestr(*cp ? cp : "."); ! 91: *dp++ = ':'; ! 92: cp = dp; ! 93: } else if (*dp++ == 0) { ! 94: pv[i++] = savestr(*cp ? cp : "."); ! 95: break; ! 96: } ! 97: pv[i] = 0; ! 98: set1("path", pv, &shvhed); ! 99: } ! 100: set("shell", SHELLPATH); ! 101: ! 102: doldol = putn(getpid()); /* For $$ */ ! 103: shtemp = strspl("/tmp/sh", doldol); /* For << */ ! 104: ! 105: /* ! 106: * Record the interrupt states from the parent process. ! 107: * If the parent is non-interruptible our hand must be forced ! 108: * or we (and our children) won't be either. ! 109: * Our children inherit termination from our parent. ! 110: * We catch it only if we are the login shell. ! 111: */ ! 112: parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */ ! 113: sigset(SIGINT, parintr); /* ... restore */ ! 114: parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */ ! 115: signal(SIGTERM, parterm); /* ... restore */ ! 116: ! 117: /* ! 118: * Process the arguments. ! 119: * ! 120: * Note that processing of -v/-x is actually delayed till after ! 121: * script processing. ! 122: * ! 123: * We set the first character of our name to be '-' if we are ! 124: * a shell running interruptible commands. Many programs which ! 125: * examine ps'es use this to filter such shells out. ! 126: */ ! 127: c--, v++; ! 128: while (c > 0 && (cp = v[0])[0] == '-') { ! 129: do switch (*cp++) { ! 130: ! 131: case 0: /* - Interruptible, no prompt */ ! 132: prompt = 0; ! 133: setintr++; ! 134: nofile++; ! 135: break; ! 136: ! 137: case 'c': /* -c Command input from arg */ ! 138: if (c == 1) ! 139: exit(0); ! 140: c--, v++; ! 141: arginp = v[0]; ! 142: prompt = 0; ! 143: nofile++; ! 144: break; ! 145: ! 146: case 'e': /* -e Exit on any error */ ! 147: exiterr++; ! 148: break; ! 149: ! 150: case 'f': /* -f Fast start */ ! 151: fast++; ! 152: break; ! 153: ! 154: case 'i': /* -i Interactive, even if !intty */ ! 155: intact++; ! 156: nofile++; ! 157: break; ! 158: ! 159: case 'n': /* -n Don't execute */ ! 160: noexec++; ! 161: break; ! 162: ! 163: case 'q': /* -q (Undoc'd) ... die on quit */ ! 164: quitit = 1; ! 165: break; ! 166: ! 167: case 's': /* -s read from std input */ ! 168: nofile++; ! 169: break; ! 170: ! 171: case 't': /* -t read one line from input */ ! 172: onelflg = 2; ! 173: prompt = 0; ! 174: nofile++; ! 175: break; ! 176: ! 177: case 'v': /* -v Echo hist expanded input */ ! 178: nverbose = 1; /* ... later */ ! 179: break; ! 180: ! 181: case 'x': /* -x Echo just before execution */ ! 182: nexececho = 1; /* ... later */ ! 183: break; ! 184: ! 185: case 'V': /* -V Echo hist expanded input */ ! 186: setNS("verbose"); /* NOW! */ ! 187: break; ! 188: ! 189: case 'X': /* -X Echo just before execution */ ! 190: setNS("echo"); /* NOW! */ ! 191: break; ! 192: ! 193: } while (*cp); ! 194: v++, c--; ! 195: } ! 196: ! 197: if (quitit) /* With all due haste, for debugging */ ! 198: signal(SIGQUIT, SIG_DFL); ! 199: ! 200: /* ! 201: * Unless prevented by -, -c, -i, -s, or -t, if there ! 202: * are remaining arguments the first of them is the name ! 203: * of a shell file from which to read commands. ! 204: */ ! 205: if (nofile == 0 && c > 0) { ! 206: nofile = open(v[0], 0); ! 207: if (nofile < 0) { ! 208: child++; /* So this ... */ ! 209: Perror(v[0]); /* ... doesn't return */ ! 210: } ! 211: file = v[0]; ! 212: SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */ ! 213: prompt = 0; ! 214: c--, v++; ! 215: } ! 216: /* ! 217: * Consider input a tty if it really is or we are interactive. ! 218: */ ! 219: intty = intact || isatty(SHIN); ! 220: /* ! 221: * Decide whether we should play with signals or not. ! 222: * If we are explicitly told (via -i, or -) or we are a login ! 223: * shell (arg0 starts with -) or the input and output are both ! 224: * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") ! 225: * Note that in only the login shell is it likely that parent ! 226: * may have set signals to be ignored ! 227: */ ! 228: if (loginsh || intact || intty && isatty(SHOUT)) ! 229: setintr = 1; ! 230: #ifdef TELL ! 231: settell(); ! 232: #endif ! 233: /* ! 234: * Save the remaining arguments in argv. ! 235: */ ! 236: setq("argv", v, &shvhed); ! 237: ! 238: /* ! 239: * Set up the prompt. ! 240: */ ! 241: if (prompt) ! 242: set("prompt", uid == 0 ? "# " : "% "); ! 243: ! 244: /* ! 245: * If we are an interactive shell, then start fiddling ! 246: * with the signals; this is a tricky game. ! 247: */ ! 248: shpgrp = getpgrp(0); ! 249: opgrp = tpgrp = -1; ! 250: oldisc = -1; ! 251: if (setintr) { ! 252: **av = '-'; ! 253: if (!quitit) /* Wary! */ ! 254: signal(SIGQUIT, SIG_IGN); ! 255: sigset(SIGINT, pintr); ! 256: sighold(SIGINT); ! 257: signal(SIGTERM, SIG_IGN); ! 258: if (quitit == 0 && arginp == 0) { ! 259: signal(SIGTSTP, SIG_IGN); ! 260: signal(SIGTTIN, SIG_IGN); ! 261: signal(SIGTTOU, SIG_IGN); ! 262: /* ! 263: * Wait till in foreground, in case someone ! 264: * stupidly runs ! 265: * csh & ! 266: * dont want to try to grab away the tty. ! 267: */ ! 268: if (isatty(FSHDIAG)) ! 269: f = FSHDIAG; ! 270: else if (isatty(FSHOUT)) ! 271: f = FSHOUT; ! 272: else if (isatty(OLDSTD)) ! 273: f = OLDSTD; ! 274: else ! 275: f = -1; ! 276: retry: ! 277: if (ioctl(f, TIOCGPGRP, &tpgrp) == 0 && tpgrp != -1) { ! 278: int ldisc; ! 279: if (tpgrp != shpgrp) { ! 280: int old = sigsys(SIGTTIN, SIG_DFL); ! 281: kill(0, SIGTTIN); ! 282: sigsys(SIGTTIN, old); ! 283: goto retry; ! 284: } ! 285: if (0 > (oldisc = ioctl (f, FIOLOOKLD, 0))) ! 286: goto notty; ! 287: if (oldisc == tty_ld) { ! 288: ldisc = ntty_ld; ! 289: if (0 > ioctl (f, FIOPOPLD, 0)) ! 290: goto notty; ! 291: else if (0 > ! 292: ioctl (f, FIOPUSHLD, &ldisc, 0)) { ! 293: ioctl(f, FIOPUSHLD, &oldisc, 0); ! 294: goto notty; ! 295: } ! 296: printf ( ! 297: "Switching to new tty driver...\n"); ! 298: } else { ! 299: int xx = 0; ! 300: /* test for newtty */ ! 301: if (ioctl(f, TIOCLBIS, &xx) > 0) ! 302: oldisc = ntty_ld; ! 303: else ! 304: oldisc = -1; ! 305: } ! 306: opgrp = shpgrp; ! 307: shpgrp = getpid(); ! 308: tpgrp = shpgrp; ! 309: ioctl(f, TIOCSPGRP, &shpgrp); ! 310: setpgrp(0, shpgrp); ! 311: dcopy(f, FSHTTY); ! 312: ioctl(FSHTTY, FIOCLEX, 0); ! 313: } else { ! 314: notty: ! 315: printf("Warning: no access to tty; thus no job control in this shell...\n"); ! 316: tpgrp = -1; ! 317: } ! 318: } ! 319: } ! 320: sigset(SIGCHLD, pchild); /* while signals not ready */ ! 321: ! 322: /* ! 323: * Set an exit here in case of an interrupt or error reading ! 324: * the shell start-up scripts. ! 325: */ ! 326: setexit(); ! 327: haderr = 0; /* In case second time through */ ! 328: if (!fast && reenter == 0) { ! 329: reenter++; ! 330: /* Will have value("home") here because set fast if don't */ ! 331: srccat(value("home"), "/.cshrc"); ! 332: if (!fast && !arginp && !onelflg) ! 333: dohash(); ! 334: if (loginsh) { ! 335: int ldisc; ! 336: srccat(value("home"), "/.login"); ! 337: } ! 338: } ! 339: ! 340: /* ! 341: * Now are ready for the -v and -x flags ! 342: */ ! 343: if (nverbose) ! 344: setNS("verbose"); ! 345: if (nexececho) ! 346: setNS("echo"); ! 347: ! 348: /* ! 349: * All the rest of the world is inside this call. ! 350: * The argument to process indicates whether it should ! 351: * catch "error unwinds". Thus if we are a interactive shell ! 352: * our call here will never return by being blown past on an error. ! 353: */ ! 354: process(setintr); ! 355: ! 356: /* ! 357: * Mop-up. ! 358: */ ! 359: if (loginsh) { ! 360: printf("logout\n"); ! 361: close(SHIN); ! 362: child++; ! 363: goodbye(); ! 364: } ! 365: exitstat(); ! 366: } ! 367: ! 368: untty() ! 369: { ! 370: ! 371: if (tpgrp > 0) { ! 372: setpgrp(0, opgrp); ! 373: ioctl(FSHTTY, TIOCSPGRP, &opgrp); ! 374: if (oldisc != -1 && oldisc != ntty_ld) { ! 375: printf("\nReverting to old tty driver...\n"); ! 376: ioctl (FSHTTY, FIOPOPLD, 0); ! 377: ioctl (FSHTTY, FIOPUSHLD, &oldisc); ! 378: } ! 379: } ! 380: } ! 381: ! 382: importpath(cp) ! 383: char *cp; ! 384: { ! 385: register int i = 0; ! 386: register char *dp; ! 387: register char **pv; ! 388: int c; ! 389: static char dot[2] = {'.', 0}; ! 390: ! 391: for (dp = cp; *dp; dp++) ! 392: if (*dp == ':') ! 393: i++; ! 394: /* ! 395: * i+2 where i is the number of colons in the path. ! 396: * There are i+1 directories in the path plus we need ! 397: * room for a zero terminator. ! 398: */ ! 399: pv = (char **) calloc(i+2, sizeof (char **)); ! 400: dp = cp; ! 401: i = 0; ! 402: if (*dp) ! 403: for (;;) { ! 404: if ((c = *dp) == ':' || c == 0) { ! 405: *dp = 0; ! 406: pv[i++] = savestr(*cp ? cp : dot); ! 407: if (c) { ! 408: cp = dp + 1; ! 409: *dp = ':'; ! 410: } else ! 411: break; ! 412: } ! 413: dp++; ! 414: } ! 415: pv[i] = 0; ! 416: set1("path", pv, &shvhed); ! 417: } ! 418: ! 419: /* ! 420: * Source to the file which is the catenation of the argument names. ! 421: */ ! 422: srccat(cp, dp) ! 423: char *cp, *dp; ! 424: { ! 425: register char *ep = strspl(cp, dp); ! 426: register int unit = dmove(open(ep, 0), -1); ! 427: ! 428: /* ioctl(unit, FIOCLEX, NULL); */ ! 429: xfree(ep); ! 430: #ifdef INGRES ! 431: srcunit(unit, 0); ! 432: #else ! 433: srcunit(unit, 1); ! 434: #endif ! 435: } ! 436: ! 437: /* ! 438: * Source to a unit. If onlyown it must be our file or our group or ! 439: * we don't chance it. This occurs on ".cshrc"s and the like. ! 440: */ ! 441: srcunit(unit, onlyown) ! 442: register int unit; ! 443: bool onlyown; ! 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: #ifdef TELL ! 453: bool otell = cantell; ! 454: #endif ! 455: struct Bin saveB; ! 456: ! 457: /* The (few) real local variables */ ! 458: jmp_buf oldexit; ! 459: int reenter; ! 460: ! 461: if (unit < 0) ! 462: return; ! 463: if (didfds) ! 464: donefds(); ! 465: if (onlyown) { ! 466: struct stat stb; ! 467: ! 468: if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_gid != getgid())) { ! 469: 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: sighold(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: /* ! 500: * Now if we are allowing commands to be interrupted, ! 501: * we let ourselves be interrupted. ! 502: */ ! 503: if (setintr) ! 504: sigrelse(SIGINT); ! 505: #ifdef TELL ! 506: settell(); ! 507: #endif ! 508: process(0); /* 0 -> blow away on errors */ ! 509: } ! 510: if (setintr) ! 511: sigrelse(SIGINT); ! 512: if (oSHIN >= 0) { ! 513: register int i; ! 514: ! 515: /* We made it to the new state... free up its storage */ ! 516: /* This code could get run twice but xfree doesn't care */ ! 517: for (i = 0; i < fblocks; i++) ! 518: xfree(fbuf[i]); ! 519: xfree((char *)fbuf); ! 520: ! 521: /* Reset input arena */ ! 522: copy((char *)&B, (char *)&saveB, sizeof B); ! 523: ! 524: close(SHIN), SHIN = oSHIN; ! 525: arginp = oarginp, onelflg = oonelflg; ! 526: evalp = oevalp, evalvec = oevalvec; ! 527: intty = oldintty, whyles = oldwhyl, gointr = ogointr; ! 528: #ifdef TELL ! 529: cantell = otell; ! 530: #endif ! 531: } ! 532: ! 533: resexit(oldexit); ! 534: /* ! 535: * If process reset() (effectively an unwind) then ! 536: * we must also unwind. ! 537: */ ! 538: if (reenter >= 2) ! 539: error(NOSTR); ! 540: } ! 541: ! 542: goodbye() ! 543: { ! 544: ! 545: if (loginsh) { ! 546: signal(SIGQUIT, SIG_IGN); ! 547: sigset(SIGINT, SIG_IGN); ! 548: signal(SIGTERM, SIG_IGN); ! 549: setintr = 0; /* No interrupts after "logout" */ ! 550: if (adrof("home")) ! 551: srccat(value("home"), "/.logout"); ! 552: } ! 553: exitstat(); ! 554: } ! 555: ! 556: exitstat() ! 557: { ! 558: ! 559: /* ! 560: * Note that if STATUS is corrupted (i.e. getn bombs) ! 561: * then error will exit directly because we poke child here. ! 562: * Otherwise we might continue unwarrantedly (sic). ! 563: */ ! 564: child++; ! 565: exit(getn(value("status"))); ! 566: } ! 567: ! 568: char *jobargv[2] = { "jobs", 0 }; ! 569: /* ! 570: * Catch an interrupt, e.g. during lexical input. ! 571: * If we are an interactive shell, we reset the interrupt catch ! 572: * immediately. In any case we drain the shell output, ! 573: * and finally go through the normal error mechanism, which ! 574: * gets a chance to make the shell go away. ! 575: */ ! 576: pintr() ! 577: { ! 578: pintr1(1); ! 579: } ! 580: ! 581: pintr1(wantnl) ! 582: bool wantnl; ! 583: { ! 584: register char **v; ! 585: ! 586: if (setintr) { ! 587: sigrelse(SIGINT); ! 588: if (pjobs) { ! 589: pjobs = 0; ! 590: printf("\n"); ! 591: dojobs(jobargv); ! 592: bferr("Interrupted"); ! 593: } ! 594: } ! 595: if (setintr) ! 596: sighold(SIGINT); ! 597: sigrelse(SIGCHLD); ! 598: draino(); ! 599: ! 600: /* ! 601: * If we have an active "onintr" then we search for the label. ! 602: * Note that if one does "onintr -" then we shan't be interruptible ! 603: * so we needn't worry about that here. ! 604: */ ! 605: if (gointr) { ! 606: search(ZGOTO, 0, gointr); ! 607: timflg = 0; ! 608: if (v = pargv) ! 609: pargv = 0, blkfree(v); ! 610: if (v = gargv) ! 611: gargv = 0, blkfree(v); ! 612: reset(); ! 613: } else if (intty && wantnl) ! 614: printf("\n"); /* Some like this, others don't */ ! 615: error(NOSTR); ! 616: } ! 617: ! 618: /* ! 619: * Process is the main driving routine for the shell. ! 620: * It runs all command processing, except for those within { ... } ! 621: * in expressions (which is run by a routine evalav in sh.exp.c which ! 622: * is a stripped down process), and `...` evaluation which is run ! 623: * also by a subset of this code in sh.glob.c in the routine backeval. ! 624: * ! 625: * The code here is a little strange because part of it is interruptible ! 626: * and hence freeing of structures appears to occur when none is necessary ! 627: * if this is ignored. ! 628: * ! 629: * Note that if catch is not set then we will unwind on any error. ! 630: * If an end-of-file occurs, we return. ! 631: */ ! 632: process(catch) ! 633: bool catch; ! 634: { ! 635: register char *cp; ! 636: jmp_buf osetexit; ! 637: struct command *t; ! 638: ! 639: getexit(osetexit); ! 640: for (;;) { ! 641: pendjob(); ! 642: paraml.next = paraml.prev = ¶ml; ! 643: paraml.word = ""; ! 644: t = 0; ! 645: setexit(); ! 646: justpr = 0; /* A chance to execute */ ! 647: ! 648: /* ! 649: * Interruptible during interactive reads ! 650: */ ! 651: if (setintr) ! 652: sigrelse(SIGINT); ! 653: ! 654: /* ! 655: * For the sake of reset() ! 656: */ ! 657: freelex(¶ml), freesyn(t), t = 0; ! 658: ! 659: if (haderr) { ! 660: if (!catch) { ! 661: /* unwind */ ! 662: doneinp = 0; ! 663: resexit(osetexit); ! 664: reset(); ! 665: } ! 666: haderr = 0; ! 667: /* ! 668: * Every error is eventually caught here or ! 669: * the shell dies. It is at this ! 670: * point that we clean up any left-over open ! 671: * files, by closing all but a fixed number ! 672: * of pre-defined files. Thus routines don't ! 673: * have to worry about leaving files open due ! 674: * to deeper errors... they will get closed here. ! 675: */ ! 676: closem(); ! 677: continue; ! 678: } ! 679: if (doneinp) { ! 680: doneinp = 0; ! 681: break; ! 682: } ! 683: if (chkstop) ! 684: chkstop--; ! 685: if (neednote) ! 686: pnote(); ! 687: if (intty && evalvec == 0) { ! 688: mailchk(); ! 689: /* ! 690: * If we are at the end of the input buffer ! 691: * then we are going to read fresh stuff. ! 692: * Otherwise, we are rereading input and don't ! 693: * need or want to prompt. ! 694: */ ! 695: if (fseekp == feobp) ! 696: if (!whyles) ! 697: for (cp = value("prompt"); *cp; cp++) ! 698: if (*cp == HIST) ! 699: printf("%d", eventno + 1); ! 700: else { ! 701: if (*cp == '\\' && cp[1] == HIST) ! 702: cp++; ! 703: putchar(*cp | QUOTE); ! 704: } ! 705: else ! 706: /* ! 707: * Prompt for forward reading loop ! 708: * body content. ! 709: */ ! 710: printf("? "); ! 711: flush(); ! 712: } ! 713: err = 0; ! 714: ! 715: /* ! 716: * Echo not only on VERBOSE, but also with history expansion. ! 717: * If there is a lexical error then we forego history echo. ! 718: */ ! 719: if (lex(¶ml) && !err && intty || adrof("verbose")) { ! 720: haderr = 1; ! 721: prlex(¶ml); ! 722: haderr = 0; ! 723: } ! 724: ! 725: /* ! 726: * The parser may lose space if interrupted. ! 727: */ ! 728: if (setintr) ! 729: sighold(SIGINT); ! 730: ! 731: /* ! 732: * Save input text on the history list if it ! 733: * is from the terminal at the top level and not ! 734: * in a loop. ! 735: */ ! 736: if (catch && intty && !whyles) ! 737: savehist(¶ml); ! 738: ! 739: /* ! 740: * Print lexical error messages. ! 741: */ ! 742: if (err) ! 743: error(err); ! 744: ! 745: /* ! 746: * If had a history command :p modifier then ! 747: * this is as far as we should go ! 748: */ ! 749: if (justpr) ! 750: reset(); ! 751: ! 752: alias(¶ml); ! 753: ! 754: /* ! 755: * Parse the words of the input into a parse tree. ! 756: */ ! 757: t = syntax(paraml.next, ¶ml, 0); ! 758: if (err) ! 759: error(err); ! 760: ! 761: /* ! 762: * Execute the parse tree ! 763: */ ! 764: execute(t, tpgrp); ! 765: ! 766: /* ! 767: * Made it! ! 768: */ ! 769: freelex(¶ml), freesyn(t); ! 770: } ! 771: resexit(osetexit); ! 772: } ! 773: ! 774: dosource(t) ! 775: register char **t; ! 776: { ! 777: register char *f; ! 778: register int u; ! 779: ! 780: t++; ! 781: f = globone(*t); ! 782: u = dmove(open(f, 0), -1); ! 783: xfree(f); ! 784: if (u < 0) ! 785: Perror(f); ! 786: srcunit(u, 0); ! 787: } ! 788: ! 789: /* ! 790: * Check for mail. ! 791: * If we are a login shell, then we don't want to tell ! 792: * about any mail file unless its been modified ! 793: * after the time we started. ! 794: * This prevents us from telling the user things he already ! 795: * knows, since the login program insists on saying ! 796: * "You have mail." ! 797: */ ! 798: mailchk() ! 799: { ! 800: register struct varent *v; ! 801: register char **vp; ! 802: time_t t; ! 803: int intvl, cnt; ! 804: struct stat stb; ! 805: bool new; ! 806: ! 807: v = adrof("mail"); ! 808: if (v == 0) ! 809: return; ! 810: time(&t); ! 811: vp = v->vec; ! 812: cnt = blklen(vp); ! 813: intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; ! 814: if (intvl < 1) ! 815: intvl = 1; ! 816: if (chktim + intvl > t) ! 817: return; ! 818: for (; *vp; vp++) { ! 819: if (stat(*vp, &stb) < 0) ! 820: continue; ! 821: new = stb.st_mtime > time0; ! 822: if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || ! 823: (stb.st_atime < chktim && stb.st_mtime < chktim) || ! 824: loginsh && !new) ! 825: continue; ! 826: if (cnt == 1) ! 827: printf("You have %smail.\n", new ? "new " : ""); ! 828: else ! 829: printf("%s in %s.\n", new ? "New mail" : "Mail", *vp); ! 830: } ! 831: chktim = t; ! 832: } ! 833: ! 834: #include <pwd.h> ! 835: /* ! 836: * Extract a home directory from the password file ! 837: * The argument points to a buffer where the name of the ! 838: * user whose home directory is sought is currently. ! 839: * We write the home directory of the user back there. ! 840: */ ! 841: gethdir(home) ! 842: char *home; ! 843: { ! 844: register struct passwd *pp = getpwnam(home); ! 845: ! 846: if (pp == 0) ! 847: return (1); ! 848: strcpy(home, pp->pw_dir); ! 849: return (0); ! 850: } ! 851: ! 852: /* ! 853: * Move the initial descriptors to their eventual ! 854: * resting places, closin all other units. ! 855: */ ! 856: initdesc() ! 857: { ! 858: ! 859: didcch = 0; /* Havent closed for child */ ! 860: didfds = 0; /* 0, 1, 2 aren't set up */ ! 861: SHIN = dcopy(0, FSHIN); ! 862: SHOUT = dcopy(1, FSHOUT); ! 863: SHDIAG = dcopy(2, FSHDIAG); ! 864: OLDSTD = dcopy(SHIN, FOLDSTD); ! 865: closem(); ! 866: } ! 867: ! 868: exit(i) ! 869: int i; ! 870: { ! 871: ! 872: untty(); ! 873: #ifdef PROF ! 874: IEH3exit(i); ! 875: #else ! 876: _exit(i); ! 877: #endif ! 878: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.