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