1#define Extern extern 2#include <sys/types.h> 3#include <signal.h> 4#define _NSIG NSIG 5#include <errno.h> 6#include <setjmp.h> 7#include "sh.h" 8/* -------- sh.c -------- */ 9/* 10 * shell 11 */ 12 13/* #include "sh.h" */ 14 15int intr; 16int inparse; 17char flags['z'-'a'+1]; 18char *flag = flags-'a'; 19char *elinep = line+sizeof(line)-5; 20char *null = ""; 21int heedint =1; 22struct env e ={line, iostack, iostack-1, 23 (xint *)NULL, FDBASE, (struct env *)NULL}; 24 25extern char **environ; /* environment pointer */ 26 27/* 28 * default shell, search rules 29 */ 30char shellname[] = "/bin/sh"; 31char search[] = ":/bin:/usr/bin"; 32 33_PROTOTYPE(void (*qflag), (int)) = SIG_IGN; 34 35_PROTOTYPE(int main, (int argc, char **argv )); 36_PROTOTYPE(int newfile, (char *s )); 37_PROTOTYPE(static char *findeq, (char *cp )); 38_PROTOTYPE(static char *cclass, (char *p, int sub )); 39_PROTOTYPE(void initarea, (void)); 40 41int main(argc, argv) 42int argc; 43register char **argv; 44{ 45 register int f; 46 register char *s; 47 int cflag; 48 char *name, **ap; 49 int (*iof)(); 50 51 initarea(); 52 if ((ap = environ) != NULL) { 53 while (*ap) 54 assign(*ap++, !COPYV); 55 for (ap = environ; *ap;) 56 export(lookup(*ap++)); 57 } 58 closeall(); 59 areanum = 1; 60 61 shell = lookup("SHELL"); 62 if (shell->value == null) 63 setval(shell, shellname); 64 export(shell); 65 66 homedir = lookup("HOME"); 67 if (homedir->value == null) 68 setval(homedir, "/"); 69 export(homedir); 70 71 setval(lookup("$"), itoa(getpid(), 5)); 72 73 path = lookup("PATH"); 74 if (path->value == null) 75 setval(path, search); 76 export(path); 77 78 ifs = lookup("IFS"); 79 if (ifs->value == null) 80 setval(ifs, " \t\n"); 81 82 prompt = lookup("PS1"); 83 if (prompt->value == null) 84#ifndef UNIXSHELL 85 setval(prompt, "$ "); 86#else 87 setval(prompt, "% "); 88#endif 89 90 if (geteuid() == 0) { 91 setval(prompt, "# "); 92 prompt->status &= ~EXPORT; 93 } 94 cprompt = lookup("PS2"); 95 if (cprompt->value == null) 96 setval(cprompt, "> "); 97 98 iof = filechar; 99 cflag = 0; 100 name = *argv++; 101 if (--argc >= 1) { 102 if(argv[0][0] == '-' && argv[0][1] != '\0') { 103 for (s = argv[0]+1; *s; s++) 104 switch (*s) { 105 case 'c': 106 prompt->status &= ~EXPORT; 107 cprompt->status &= ~EXPORT; 108 setval(prompt, ""); 109 setval(cprompt, ""); 110 cflag = 1; 111 if (--argc > 0) 112 PUSHIO(aword, *++argv, iof = nlchar); 113 break; 114 115 case 'q': 116 qflag = SIG_DFL; 117 break; 118 119 case 's': 120 /* standard input */ 121 break; 122 123 case 't': 124 prompt->status &= ~EXPORT; 125 setval(prompt, ""); 126 iof = linechar; 127 break; 128 129 case 'i': 130 talking++; 131 default: 132 if (*s>='a' && *s<='z') 133 flag[*s]++; 134 } 135 } else { 136 argv--; 137 argc++; 138 } 139 if (iof == filechar && --argc > 0) { 140 setval(prompt, ""); 141 setval(cprompt, ""); 142 prompt->status &= ~EXPORT; 143 cprompt->status &= ~EXPORT; 144 if (newfile(name = *++argv)) 145 exit(1); 146 } 147 } 148 setdash(); 149 if (e.iop < iostack) { 150 PUSHIO(afile, 0, iof); 151 if (isatty(0) && isatty(1) && !cflag) 152 talking++; 153 } 154 signal(SIGQUIT, qflag); 155 if (name && name[0] == '-') { 156 talking++; 157 if ((f = open(".profile", 0)) >= 0) 158 next(remap(f)); 159 if ((f = open("/etc/profile", 0)) >= 0) 160 next(remap(f)); 161 } 162 if (talking) 163 signal(SIGTERM, sig); 164 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 165 signal(SIGINT, onintr); 166 dolv = argv; 167 dolc = argc; 168 dolv[0] = name; 169 if (dolc > 1) 170 for (ap = ++argv; --argc > 0;) 171 if (assign(*ap = *argv++, !COPYV)) 172 dolc--; /* keyword */ 173 else 174 ap++; 175 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); 176 177 for (;;) { 178 if (talking && e.iop <= iostack) 179 prs(prompt->value); 180 onecommand(); 181 } 182} 183 184void 185setdash() 186{ 187 register char *cp, c; 188 char m['z'-'a'+1]; 189 190 cp = m; 191 for (c='a'; c<='z'; c++) 192 if (flag[c]) 193 *cp++ = c; 194 *cp = 0; 195 setval(lookup("-"), m); 196} 197 198int 199newfile(s) 200register char *s; 201{ 202 register f; 203 204 if (strcmp(s, "-") != 0) { 205 f = open(s, 0); 206 if (f < 0) { 207 prs(s); 208 err(": cannot open"); 209 return(1); 210 } 211 } else 212 f = 0; 213 next(remap(f)); 214 return(0); 215} 216 217void 218onecommand() 219{ 220 register i; 221 jmp_buf m1; 222 223 while (e.oenv) 224 quitenv(); 225 areanum = 1; 226 freehere(areanum); 227 freearea(areanum); 228 garbage(); 229 wdlist = 0; 230 iolist = 0; 231 e.errpt = 0; 232 e.linep = line; 233 yynerrs = 0; 234 multiline = 0; 235 inparse = 1; 236 intr = 0; 237 execflg = 0; 238 setjmp(failpt = m1); /* Bruce Evans' fix */ 239 if (setjmp(failpt = m1) || yyparse() || intr) { 240 while (e.oenv) 241 quitenv(); 242 scraphere(); 243 if (!talking && intr) 244 leave(); 245 inparse = 0; 246 intr = 0; 247 return; 248 } 249 inparse = 0; 250 brklist = 0; 251 intr = 0; 252 execflg = 0; 253 if (!flag['n']) 254 execute(outtree, NOPIPE, NOPIPE, 0); 255 if (!talking && intr) { 256 execflg = 0; 257 leave(); 258 } 259 if ((i = trapset) != 0) { 260 trapset = 0; 261 runtrap(i); 262 } 263} 264 265void 266fail() 267{ 268 longjmp(failpt, 1); 269 /* NOTREACHED */ 270} 271 272void 273leave() 274{ 275 if (execflg) 276 fail(); 277 scraphere(); 278 freehere(1); 279 runtrap(0); 280 exit(exstat); 281 /* NOTREACHED */ 282} 283 284void 285warn(s) 286register char *s; 287{ 288 if(*s) { 289 prs(s); 290 exstat = -1; 291 } 292 prs("\n"); 293 if (flag['e']) 294 leave(); 295} 296 297void 298err(s) 299char *s; 300{ 301 warn(s); 302 if (flag['n']) 303 return; 304 if (!talking) 305 leave(); 306 if (e.errpt) 307 longjmp(e.errpt, 1); 308 closeall(); 309 e.iop = e.iobase = iostack; 310} 311 312int 313newenv(f) 314int f; 315{ 316 register struct env *ep; 317 318 if (f) { 319 quitenv(); 320 return(1); 321 } 322 ep = (struct env *) space(sizeof(*ep)); 323 if (ep == NULL) { 324 while (e.oenv) 325 quitenv(); 326 fail(); 327 } 328 *ep = e; 329 e.oenv = ep; 330 e.errpt = errpt; 331 return(0); 332} 333 334void 335quitenv() 336{ 337 register struct env *ep; 338 register fd; 339 340 if ((ep = e.oenv) != NULL) { 341 fd = e.iofd; 342 e = *ep; 343 /* should close `'d files */ 344 DELETE(ep); 345 while (--fd >= e.iofd) 346 close(fd); 347 } 348} 349 350/* 351 * Is any character from s1 in s2? 352 */ 353int 354anys(s1, s2) 355register char *s1, *s2; 356{ 357 while (*s1) 358 if (any(*s1++, s2)) 359 return(1); 360 return(0); 361} 362 363/* 364 * Is character c in s? 365 */ 366int 367any(c, s) 368register int c; 369register char *s; 370{ 371 while (*s) 372 if (*s++ == c) 373 return(1); 374 return(0); 375} 376 377char * 378putn(n) 379register int n; 380{ 381 return(itoa(n, -1)); 382} 383 384char * 385itoa(u, n) 386register unsigned u; 387int n; 388{ 389 register char *cp; 390 static char s[20]; 391 int m; 392 393 m = 0; 394 if (n < 0 && (int) u < 0) { 395 m++; 396 u = -u; 397 } 398 cp = s+sizeof(s); 399 *--cp = 0; 400 do { 401 *--cp = u%10 + '0'; 402 u /= 10; 403 } while (--n > 0 || u); 404 if (m) 405 *--cp = '-'; 406 return(cp); 407} 408 409void 410next(f) 411int f; 412{ 413 PUSHIO(afile, f, filechar); 414} 415 416void 417onintr(s) 418int s; /* ANSI C requires a parameter */ 419{ 420 signal(SIGINT, onintr); 421 intr = 1; 422 if (talking) { 423 if (inparse) { 424 prs("\n"); 425 fail(); 426 } 427 } 428 else if (heedint) { 429 execflg = 0; 430 leave(); 431 } 432} 433 434int 435letter(c) 436register c; 437{ 438 return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'); 439} 440 441int 442digit(c) 443register c; 444{ 445 return(c >= '0' && c <= '9'); 446} 447 448int 449letnum(c) 450register c; 451{ 452 return(letter(c) || digit(c)); 453} 454 455char * 456space(n) 457int n; 458{ 459 register char *cp; 460 461 if ((cp = getcell(n)) == 0) 462 err("out of string space"); 463 return(cp); 464} 465 466char * 467strsave(s, a) 468register char *s; 469int a; 470{ 471 register char *cp, *xp; 472 473 if ((cp = space(strlen(s)+1)) != NULL) { 474 setarea((char *)cp, a); 475 for (xp = cp; (*xp++ = *s++) != '\0';) 476 ; 477 return(cp); 478 } 479 return(""); 480} 481 482void 483xfree(s) 484register char *s; 485{ 486 DELETE(s); 487} 488 489/* 490 * trap handling 491 */ 492void 493sig(i) 494register int i; 495{ 496 trapset = i; 497 signal(i, sig); 498} 499 500void runtrap(i) 501int i; 502{ 503 char *trapstr; 504 505 if ((trapstr = trap[i]) == NULL) 506 return; 507 if (i == 0) 508 trap[i] = 0; 509 RUN(aword, trapstr, nlchar); 510} 511 512/* -------- var.c -------- */ 513/* #include "sh.h" */ 514 515/* 516 * Find the given name in the dictionary 517 * and return its value. If the name was 518 * not previously there, enter it now and 519 * return a null value. 520 */ 521struct var * 522lookup(n) 523register char *n; 524{ 525 register struct var *vp; 526 register char *cp; 527 register int c; 528 static struct var dummy; 529 530 if (digit(*n)) { 531 dummy.name = n; 532 for (c = 0; digit(*n) && c < 1000; n++) 533 c = c*10 + *n-'0'; 534 dummy.status = RONLY; 535 dummy.value = c <= dolc? dolv[c]: null; 536 return(&dummy); 537 } 538 for (vp = vlist; vp; vp = vp->next) 539 if (eqname(vp->name, n)) 540 return(vp); 541 cp = findeq(n); 542 vp = (struct var *)space(sizeof(*vp)); 543 if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) { 544 dummy.name = dummy.value = ""; 545 return(&dummy); 546 } 547 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++) 548 ; 549 if (*cp == 0) 550 *cp = '='; 551 *++cp = 0; 552 setarea((char *)vp, 0); 553 setarea((char *)vp->name, 0); 554 vp->value = null; 555 vp->next = vlist; 556 vp->status = GETCELL; 557 vlist = vp; 558 return(vp); 559} 560 561/* 562 * give variable at `vp' the value `val'. 563 */ 564void 565setval(vp, val) 566struct var *vp; 567char *val; 568{ 569 nameval(vp, val, (char *)NULL); 570} 571 572/* 573 * if name is not NULL, it must be 574 * a prefix of the space `val', 575 * and end with `='. 576 * this is all so that exporting 577 * values is reasonably painless. 578 */ 579void 580nameval(vp, val, name) 581register struct var *vp; 582char *val, *name; 583{ 584 register char *cp, *xp; 585 char *nv; 586 int fl; 587 588 if (vp->status & RONLY) { 589 for (xp = vp->name; *xp && *xp != '=';) 590 putc(*xp++); 591 err(" is read-only"); 592 return; 593 } 594 fl = 0; 595 if (name == NULL) { 596 xp = space(strlen(vp->name)+strlen(val)+2); 597 if (xp == 0) 598 return; 599 /* make string: name=value */ 600 setarea((char *)xp, 0); 601 name = xp; 602 for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++) 603 ; 604 if (*xp++ == 0) 605 xp[-1] = '='; 606 nv = xp; 607 for (cp = val; (*xp++ = *cp++) != '\0';) 608 ; 609 val = nv; 610 fl = GETCELL; 611 } 612 if (vp->status & GETCELL) 613 xfree(vp->name); /* form new string `name=value' */ 614 vp->name = name; 615 vp->value = val; 616 vp->status |= fl; 617} 618 619void 620export(vp) 621struct var *vp; 622{ 623 vp->status |= EXPORT; 624} 625 626void 627ronly(vp) 628struct var *vp; 629{ 630 if (letter(vp->name[0])) /* not an internal symbol ($# etc) */ 631 vp->status |= RONLY; 632} 633 634int 635isassign(s) 636register char *s; 637{ 638 if (!letter((int)*s)) 639 return(0); 640 for (; *s != '='; s++) 641 if (*s == 0 || !letnum(*s)) 642 return(0); 643 return(1); 644} 645 646int 647assign(s, cf) 648register char *s; 649int cf; 650{ 651 register char *cp; 652 struct var *vp; 653 654 if (!letter(*s)) 655 return(0); 656 for (cp = s; *cp != '='; cp++) 657 if (*cp == 0 || !letnum(*cp)) 658 return(0); 659 vp = lookup(s); 660 nameval(vp, ++cp, cf == COPYV? (char *)NULL: s); 661 if (cf != COPYV) 662 vp->status &= ~GETCELL; 663 return(1); 664} 665 666int 667checkname(cp) 668register char *cp; 669{ 670 if (!letter(*cp++)) 671 return(0); 672 while (*cp) 673 if (!letnum(*cp++)) 674 return(0); 675 return(1); 676} 677 678void 679putvlist(f, out) 680register int f, out; 681{ 682 register struct var *vp; 683 684 for (vp = vlist; vp; vp = vp->next) 685 if (vp->status & f && letter(*vp->name)) { 686 if (vp->status & EXPORT) 687 write(out, "export ", 7); 688 if (vp->status & RONLY) 689 write(out, "readonly ", 9); 690 write(out, vp->name, (int)(findeq(vp->name) - vp->name)); 691 write(out, "\n", 1); 692 } 693} 694 695int 696eqname(n1, n2) 697register char *n1, *n2; 698{ 699 for (; *n1 != '=' && *n1 != 0; n1++) 700 if (*n2++ != *n1) 701 return(0); 702 return(*n2 == 0 || *n2 == '='); 703} 704 705static char * 706findeq(cp) 707register char *cp; 708{ 709 while (*cp != '\0' && *cp != '=') 710 cp++; 711 return(cp); 712} 713 714/* -------- gmatch.c -------- */ 715/* 716 * int gmatch(string, pattern) 717 * char *string, *pattern; 718 * 719 * Match a pattern as in sh(1). 720 */ 721 722#define CMASK 0377 723#define QUOTE 0200 724#define QMASK (CMASK&~QUOTE) 725#define NOT '!' /* might use ^ */ 726 727int 728gmatch(s, p) 729register char *s, *p; 730{ 731 register int sc, pc; 732 733 if (s == NULL || p == NULL) 734 return(0); 735 while ((pc = *p++ & CMASK) != '\0') { 736 sc = *s++ & QMASK; 737 switch (pc) { 738 case '[': 739 if ((p = cclass(p, sc)) == NULL) 740 return(0); 741 break; 742 743 case '?': 744 if (sc == 0) 745 return(0); 746 break; 747 748 case '*': 749 s--; 750 do { 751 if (*p == '\0' || gmatch(s, p)) 752 return(1); 753 } while (*s++ != '\0'); 754 return(0); 755 756 default: 757 if (sc != (pc&~QUOTE)) 758 return(0); 759 } 760 } 761 return(*s == 0); 762} 763 764static char * 765cclass(p, sub) 766register char *p; 767register int sub; 768{ 769 register int c, d, not, found; 770 771 if ((not = *p == NOT) != 0) 772 p++; 773 found = not; 774 do { 775 if (*p == '\0') 776 return((char *)NULL); 777 c = *p & CMASK; 778 if (p[1] == '-' && p[2] != ']') { 779 d = p[2] & CMASK; 780 p++; 781 } else 782 d = c; 783 if (c == sub || (c <= sub && sub <= d)) 784 found = !not; 785 } while (*++p != ']'); 786 return(found? p+1: (char *)NULL); 787} 788 789/* -------- area.c -------- */ 790#define REGSIZE sizeof(struct region) 791#define GROWBY 256 792#undef SHRINKBY 64 793#define FREE 32767 794#define BUSY 0 795#define ALIGN (sizeof(int)-1) 796 797/* #include "area.h" */ 798 799struct region { 800 struct region *next; 801 int area; 802}; 803 804/* 805 * All memory between (char *)areabot and (char *)(areatop+1) is 806 * exclusively administered by the area management routines. 807 * It is assumed that sbrk() and brk() manipulate the high end. 808 */ 809static struct region *areabot; /* bottom of area */ 810static struct region *areatop; /* top of area */ 811static struct region *areanxt; /* starting point of scan */ 812 813void 814initarea() 815{ 816 while ((int)sbrk(0) & ALIGN) 817 sbrk(1); 818 areabot = (struct region *)sbrk(REGSIZE); 819 areabot->next = areabot; 820 areabot->area = BUSY; 821 areatop = areabot; 822 areanxt = areabot; 823} 824 825char * 826getcell(nbytes) 827unsigned nbytes; 828{ 829 register int nregio; 830 register struct region *p, *q; 831 register i; 832 833 if (nbytes == 0) 834 abort(); /* silly and defeats the algorithm */ 835 /* 836 * round upwards and add administration area 837 */ 838 nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1; 839 for (p = areanxt;;) { 840 if (p->area > areanum) { 841 /* 842 * merge free cells 843 */ 844 while ((q = p->next)->area > areanum && q != areanxt) 845 p->next = q->next; 846 /* 847 * exit loop if cell big enough 848 */ 849 if (q >= p + nregio) 850 goto found; 851 } 852 p = p->next; 853 if (p == areanxt) 854 break; 855 } 856 i = nregio >= GROWBY ? nregio : GROWBY; 857 p = (struct region *)sbrk(i * REGSIZE); 858 if (p == (struct region *)-1) 859 return((char *)NULL); 860 p--; 861 if (p != areatop) 862 abort(); /* allocated areas are contiguous */ 863 q = p + i; 864 p->next = q; 865 p->area = FREE; 866 q->next = areabot; 867 q->area = BUSY; 868 areatop = q; 869found: 870 /* 871 * we found a FREE area big enough, pointed to by 'p', and up to 'q' 872 */ 873 areanxt = p + nregio; 874 if (areanxt < q) { 875 /* 876 * split into requested area and rest 877 */ 878 if (areanxt+1 > q) 879 abort(); /* insufficient space left for admin */ 880 areanxt->next = q; 881 areanxt->area = FREE; 882 p->next = areanxt; 883 } 884 p->area = areanum; 885 return((char *)(p+1)); 886} 887 888void 889freecell(cp) 890char *cp; 891{ 892 register struct region *p; 893 894 if ((p = (struct region *)cp) != NULL) { 895 p--; 896 if (p < areanxt) 897 areanxt = p; 898 p->area = FREE; 899 } 900} 901 902void 903freearea(a) 904register int a; 905{ 906 register struct region *p, *top; 907 908 top = areatop; 909 for (p = areabot; p != top; p = p->next) 910 if (p->area >= a) 911 p->area = FREE; 912} 913 914void 915setarea(cp,a) 916char *cp; 917int a; 918{ 919 register struct region *p; 920 921 if ((p = (struct region *)cp) != NULL) 922 (p-1)->area = a; 923} 924 925int 926getarea(cp) 927char *cp; 928{ 929 return ((struct region*)cp-1)->area; 930} 931 932void 933garbage() 934{ 935 register struct region *p, *q, *top; 936 937 top = areatop; 938 for (p = areabot; p != top; p = p->next) { 939 if (p->area > areanum) { 940 while ((q = p->next)->area > areanum) 941 p->next = q->next; 942 areanxt = p; 943 } 944 } 945#ifdef SHRINKBY 946 if (areatop >= q + SHRINKBY && q->area > areanum) { 947 brk((char *)(q+1)); 948 q->next = areabot; 949 q->area = BUSY; 950 areatop = q; 951 } 952#endif 953} 954