00001 #define Extern extern
00002 #include <sys/types.h>
00003 #include <signal.h>
00004 #include <errno.h>
00005 #include <setjmp.h>
00006 #include "sh.h"
00007
00008
00009
00010
00011
00012
00013
00014 int intr;
00015 int inparse;
00016 char flags['z'-'a'+1];
00017 char *flag = flags-'a';
00018 char *elinep = line+sizeof(line)-5;
00019 char *null = "";
00020 int heedint =1;
00021 struct env e ={line, iostack, iostack-1,
00022 (xint *)NULL, FDBASE, (struct env *)NULL};
00023
00024 extern char **environ;
00025
00026
00027
00028
00029 char shellname[] = "/bin/sh";
00030 char search[] = ":/bin:/usr/bin";
00031
00032 _PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
00033
00034 _PROTOTYPE(int main, (int argc, char **argv ));
00035 _PROTOTYPE(int newfile, (char *s ));
00036 _PROTOTYPE(static char *findeq, (char *cp ));
00037 _PROTOTYPE(static char *cclass, (char *p, int sub ));
00038 _PROTOTYPE(void initarea, (void));
00039
00040 int main(argc, argv)
00041 int argc;
00042 register char **argv;
00043 {
00044 register int f;
00045 register char *s;
00046 int cflag;
00047 char *name, **ap;
00048 int (*iof)();
00049
00050 initarea();
00051 if ((ap = environ) != NULL) {
00052 while (*ap)
00053 assign(*ap++, !COPYV);
00054 for (ap = environ; *ap;)
00055 export(lookup(*ap++));
00056 }
00057 closeall();
00058 areanum = 1;
00059
00060 shell = lookup("SHELL");
00061 if (shell->value == null)
00062 setval(shell, shellname);
00063 export(shell);
00064
00065 homedir = lookup("HOME");
00066 if (homedir->value == null)
00067 setval(homedir, "/");
00068 export(homedir);
00069
00070 setval(lookup("$"), itoa(getpid(), 5));
00071
00072 path = lookup("PATH");
00073 if (path->value == null)
00074 setval(path, search);
00075 export(path);
00076
00077 ifs = lookup("IFS");
00078 if (ifs->value == null)
00079 setval(ifs, " \t\n");
00080
00081 prompt = lookup("PS1");
00082 if (prompt->value == null)
00083 #ifndef UNIXSHELL
00084 setval(prompt, "$ ");
00085 #else
00086 setval(prompt, "% ");
00087 #endif
00088
00089 if (geteuid() == 0) {
00090 setval(prompt, "# ");
00091 prompt->status &= ~EXPORT;
00092 }
00093 cprompt = lookup("PS2");
00094 if (cprompt->value == null)
00095 setval(cprompt, "> ");
00096
00097 iof = filechar;
00098 cflag = 0;
00099 name = *argv++;
00100 if (--argc >= 1) {
00101 if(argv[0][0] == '-' && argv[0][1] != '\0') {
00102 for (s = argv[0]+1; *s; s++)
00103 switch (*s) {
00104 case 'c':
00105 prompt->status &= ~EXPORT;
00106 cprompt->status &= ~EXPORT;
00107 setval(prompt, "");
00108 setval(cprompt, "");
00109 cflag = 1;
00110 if (--argc > 0)
00111 PUSHIO(aword, *++argv, iof = nlchar);
00112 break;
00113
00114 case 'q':
00115 qflag = SIG_DFL;
00116 break;
00117
00118 case 's':
00119
00120 break;
00121
00122 case 't':
00123 prompt->status &= ~EXPORT;
00124 setval(prompt, "");
00125 iof = linechar;
00126 break;
00127
00128 case 'i':
00129 talking++;
00130 default:
00131 if (*s>='a' && *s<='z')
00132 flag[*s]++;
00133 }
00134 } else {
00135 argv--;
00136 argc++;
00137 }
00138 if (iof == filechar && --argc > 0) {
00139 setval(prompt, "");
00140 setval(cprompt, "");
00141 prompt->status &= ~EXPORT;
00142 cprompt->status &= ~EXPORT;
00143 if (newfile(name = *++argv))
00144 exit(1);
00145 }
00146 }
00147 setdash();
00148 if (e.iop < iostack) {
00149 PUSHIO(afile, 0, iof);
00150 if (isatty(0) && isatty(1) && !cflag)
00151 talking++;
00152 }
00153 signal(SIGQUIT, qflag);
00154 if (name && name[0] == '-') {
00155 talking++;
00156 if ((f = open(".profile", 0)) >= 0)
00157 next(remap(f));
00158 if ((f = open("/etc/profile", 0)) >= 0)
00159 next(remap(f));
00160 }
00161 if (talking)
00162 signal(SIGTERM, sig);
00163 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
00164 signal(SIGINT, onintr);
00165 dolv = argv;
00166 dolc = argc;
00167 dolv[0] = name;
00168 if (dolc > 1)
00169 for (ap = ++argv; --argc > 0;)
00170 if (assign(*ap = *argv++, !COPYV))
00171 dolc--;
00172 else
00173 ap++;
00174 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
00175
00176 for (;;) {
00177 if (talking && e.iop <= iostack)
00178 prs(prompt->value);
00179 onecommand();
00180 }
00181 }
00182
00183 void
00184 setdash()
00185 {
00186 register char *cp, c;
00187 char m['z'-'a'+1];
00188
00189 cp = m;
00190 for (c='a'; c<='z'; c++)
00191 if (flag[c])
00192 *cp++ = c;
00193 *cp = 0;
00194 setval(lookup("-"), m);
00195 }
00196
00197 int
00198 newfile(s)
00199 register char *s;
00200 {
00201 register f;
00202
00203 if (strcmp(s, "-") != 0) {
00204 f = open(s, 0);
00205 if (f < 0) {
00206 prs(s);
00207 err(": cannot open");
00208 return(1);
00209 }
00210 } else
00211 f = 0;
00212 next(remap(f));
00213 return(0);
00214 }
00215
00216 void
00217 onecommand()
00218 {
00219 register i;
00220 jmp_buf m1;
00221
00222 while (e.oenv)
00223 quitenv();
00224 areanum = 1;
00225 freehere(areanum);
00226 freearea(areanum);
00227 garbage();
00228 wdlist = 0;
00229 iolist = 0;
00230 e.errpt = 0;
00231 e.linep = line;
00232 yynerrs = 0;
00233 multiline = 0;
00234 inparse = 1;
00235 intr = 0;
00236 execflg = 0;
00237 setjmp(failpt = m1);
00238 if (setjmp(failpt = m1) || yyparse() || intr) {
00239 while (e.oenv)
00240 quitenv();
00241 scraphere();
00242 if (!talking && intr)
00243 leave();
00244 inparse = 0;
00245 intr = 0;
00246 return;
00247 }
00248 inparse = 0;
00249 brklist = 0;
00250 intr = 0;
00251 execflg = 0;
00252 if (!flag['n'])
00253 execute(outtree, NOPIPE, NOPIPE, 0);
00254 if (!talking && intr) {
00255 execflg = 0;
00256 leave();
00257 }
00258 if ((i = trapset) != 0) {
00259 trapset = 0;
00260 runtrap(i);
00261 }
00262 }
00263
00264 void
00265 fail()
00266 {
00267 longjmp(failpt, 1);
00268
00269 }
00270
00271 void
00272 leave()
00273 {
00274 if (execflg)
00275 fail();
00276 scraphere();
00277 freehere(1);
00278 runtrap(0);
00279 exit(exstat);
00280
00281 }
00282
00283 void
00284 warn(s)
00285 register char *s;
00286 {
00287 if(*s) {
00288 prs(s);
00289 exstat = -1;
00290 }
00291 prs("\n");
00292 if (flag['e'])
00293 leave();
00294 }
00295
00296 void
00297 err(s)
00298 char *s;
00299 {
00300 warn(s);
00301 if (flag['n'])
00302 return;
00303 if (!talking)
00304 leave();
00305 if (e.errpt)
00306 longjmp(e.errpt, 1);
00307 closeall();
00308 e.iop = e.iobase = iostack;
00309 }
00310
00311 int
00312 newenv(f)
00313 int f;
00314 {
00315 register struct env *ep;
00316
00317 if (f) {
00318 quitenv();
00319 return(1);
00320 }
00321 ep = (struct env *) space(sizeof(*ep));
00322 if (ep == NULL) {
00323 while (e.oenv)
00324 quitenv();
00325 fail();
00326 }
00327 *ep = e;
00328 e.oenv = ep;
00329 e.errpt = errpt;
00330 return(0);
00331 }
00332
00333 void
00334 quitenv()
00335 {
00336 register struct env *ep;
00337 register fd;
00338
00339 if ((ep = e.oenv) != NULL) {
00340 fd = e.iofd;
00341 e = *ep;
00342
00343 DELETE(ep);
00344 while (--fd >= e.iofd)
00345 close(fd);
00346 }
00347 }
00348
00349
00350
00351
00352 int
00353 anys(s1, s2)
00354 register char *s1, *s2;
00355 {
00356 while (*s1)
00357 if (any(*s1++, s2))
00358 return(1);
00359 return(0);
00360 }
00361
00362
00363
00364
00365 int
00366 any(c, s)
00367 register int c;
00368 register char *s;
00369 {
00370 while (*s)
00371 if (*s++ == c)
00372 return(1);
00373 return(0);
00374 }
00375
00376 char *
00377 putn(n)
00378 register int n;
00379 {
00380 return(itoa(n, -1));
00381 }
00382
00383 char *
00384 itoa(u, n)
00385 register unsigned u;
00386 int n;
00387 {
00388 register char *cp;
00389 static char s[20];
00390 int m;
00391
00392 m = 0;
00393 if (n < 0 && (int) u < 0) {
00394 m++;
00395 u = -u;
00396 }
00397 cp = s+sizeof(s);
00398 *--cp = 0;
00399 do {
00400 *--cp = u%10 + '0';
00401 u /= 10;
00402 } while (--n > 0 || u);
00403 if (m)
00404 *--cp = '-';
00405 return(cp);
00406 }
00407
00408 void
00409 next(f)
00410 int f;
00411 {
00412 PUSHIO(afile, f, filechar);
00413 }
00414
00415 void
00416 onintr(s)
00417 int s;
00418 {
00419 signal(SIGINT, onintr);
00420 intr = 1;
00421 if (talking) {
00422 if (inparse) {
00423 prs("\n");
00424 fail();
00425 }
00426 }
00427 else if (heedint) {
00428 execflg = 0;
00429 leave();
00430 }
00431 }
00432
00433 int
00434 letter(c)
00435 register c;
00436 {
00437 return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
00438 }
00439
00440 int
00441 digit(c)
00442 register c;
00443 {
00444 return(c >= '0' && c <= '9');
00445 }
00446
00447 int
00448 letnum(c)
00449 register c;
00450 {
00451 return(letter(c) || digit(c));
00452 }
00453
00454 char *
00455 space(n)
00456 int n;
00457 {
00458 register char *cp;
00459
00460 if ((cp = getcell(n)) == 0)
00461 err("out of string space");
00462 return(cp);
00463 }
00464
00465 char *
00466 strsave(s, a)
00467 register char *s;
00468 int a;
00469 {
00470 register char *cp, *xp;
00471
00472 if ((cp = space(strlen(s)+1)) != NULL) {
00473 setarea((char *)cp, a);
00474 for (xp = cp; (*xp++ = *s++) != '\0';)
00475 ;
00476 return(cp);
00477 }
00478 return("");
00479 }
00480
00481 void
00482 xfree(s)
00483 register char *s;
00484 {
00485 DELETE(s);
00486 }
00487
00488
00489
00490
00491 void
00492 sig(i)
00493 register int i;
00494 {
00495 trapset = i;
00496 signal(i, sig);
00497 }
00498
00499 void runtrap(i)
00500 int i;
00501 {
00502 char *trapstr;
00503
00504 if ((trapstr = trap[i]) == NULL)
00505 return;
00506 if (i == 0)
00507 trap[i] = 0;
00508 RUN(aword, trapstr, nlchar);
00509 }
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 struct var *
00521 lookup(n)
00522 register char *n;
00523 {
00524 register struct var *vp;
00525 register char *cp;
00526 register int c;
00527 static struct var dummy;
00528
00529 if (digit(*n)) {
00530 dummy.name = n;
00531 for (c = 0; digit(*n) && c < 1000; n++)
00532 c = c*10 + *n-'0';
00533 dummy.status = RONLY;
00534 dummy.value = c <= dolc? dolv[c]: null;
00535 return(&dummy);
00536 }
00537 for (vp = vlist; vp; vp = vp->next)
00538 if (eqname(vp->name, n))
00539 return(vp);
00540 cp = findeq(n);
00541 vp = (struct var *)space(sizeof(*vp));
00542 if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
00543 dummy.name = dummy.value = "";
00544 return(&dummy);
00545 }
00546 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
00547 ;
00548 if (*cp == 0)
00549 *cp = '=';
00550 *++cp = 0;
00551 setarea((char *)vp, 0);
00552 setarea((char *)vp->name, 0);
00553 vp->value = null;
00554 vp->next = vlist;
00555 vp->status = GETCELL;
00556 vlist = vp;
00557 return(vp);
00558 }
00559
00560
00561
00562
00563 void
00564 setval(vp, val)
00565 struct var *vp;
00566 char *val;
00567 {
00568 nameval(vp, val, (char *)NULL);
00569 }
00570
00571
00572
00573
00574
00575
00576
00577
00578 void
00579 nameval(vp, val, name)
00580 register struct var *vp;
00581 char *val, *name;
00582 {
00583 register char *cp, *xp;
00584 char *nv;
00585 int fl;
00586
00587 if (vp->status & RONLY) {
00588 for (xp = vp->name; *xp && *xp != '=';)
00589 putc(*xp++);
00590 err(" is read-only");
00591 return;
00592 }
00593 fl = 0;
00594 if (name == NULL) {
00595 xp = space(strlen(vp->name)+strlen(val)+2);
00596 if (xp == 0)
00597 return;
00598
00599 setarea((char *)xp, 0);
00600 name = xp;
00601 for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
00602 ;
00603 if (*xp++ == 0)
00604 xp[-1] = '=';
00605 nv = xp;
00606 for (cp = val; (*xp++ = *cp++) != '\0';)
00607 ;
00608 val = nv;
00609 fl = GETCELL;
00610 }
00611 if (vp->status & GETCELL)
00612 xfree(vp->name);
00613 vp->name = name;
00614 vp->value = val;
00615 vp->status |= fl;
00616 }
00617
00618 void
00619 export(vp)
00620 struct var *vp;
00621 {
00622 vp->status |= EXPORT;
00623 }
00624
00625 void
00626 ronly(vp)
00627 struct var *vp;
00628 {
00629 if (letter(vp->name[0]))
00630 vp->status |= RONLY;
00631 }
00632
00633 int
00634 isassign(s)
00635 register char *s;
00636 {
00637 if (!letter((int)*s))
00638 return(0);
00639 for (; *s != '='; s++)
00640 if (*s == 0 || !letnum(*s))
00641 return(0);
00642 return(1);
00643 }
00644
00645 int
00646 assign(s, cf)
00647 register char *s;
00648 int cf;
00649 {
00650 register char *cp;
00651 struct var *vp;
00652
00653 if (!letter(*s))
00654 return(0);
00655 for (cp = s; *cp != '='; cp++)
00656 if (*cp == 0 || !letnum(*cp))
00657 return(0);
00658 vp = lookup(s);
00659 nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
00660 if (cf != COPYV)
00661 vp->status &= ~GETCELL;
00662 return(1);
00663 }
00664
00665 int
00666 checkname(cp)
00667 register char *cp;
00668 {
00669 if (!letter(*cp++))
00670 return(0);
00671 while (*cp)
00672 if (!letnum(*cp++))
00673 return(0);
00674 return(1);
00675 }
00676
00677 void
00678 putvlist(f, out)
00679 register int f, out;
00680 {
00681 register struct var *vp;
00682
00683 for (vp = vlist; vp; vp = vp->next)
00684 if (vp->status & f && letter(*vp->name)) {
00685 if (vp->status & EXPORT)
00686 write(out, "export ", 7);
00687 if (vp->status & RONLY)
00688 write(out, "readonly ", 9);
00689 write(out, vp->name, (int)(findeq(vp->name) - vp->name));
00690 write(out, "\n", 1);
00691 }
00692 }
00693
00694 int
00695 eqname(n1, n2)
00696 register char *n1, *n2;
00697 {
00698 for (; *n1 != '=' && *n1 != 0; n1++)
00699 if (*n2++ != *n1)
00700 return(0);
00701 return(*n2 == 0 || *n2 == '=');
00702 }
00703
00704 static char *
00705 findeq(cp)
00706 register char *cp;
00707 {
00708 while (*cp != '\0' && *cp != '=')
00709 cp++;
00710 return(cp);
00711 }
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721 #define CMASK 0377
00722 #define QUOTE 0200
00723 #define QMASK (CMASK&~QUOTE)
00724 #define NOT '!'
00725
00726 int
00727 gmatch(s, p)
00728 register char *s, *p;
00729 {
00730 register int sc, pc;
00731
00732 if (s == NULL || p == NULL)
00733 return(0);
00734 while ((pc = *p++ & CMASK) != '\0') {
00735 sc = *s++ & QMASK;
00736 switch (pc) {
00737 case '[':
00738 if ((p = cclass(p, sc)) == NULL)
00739 return(0);
00740 break;
00741
00742 case '?':
00743 if (sc == 0)
00744 return(0);
00745 break;
00746
00747 case '*':
00748 s--;
00749 do {
00750 if (*p == '\0' || gmatch(s, p))
00751 return(1);
00752 } while (*s++ != '\0');
00753 return(0);
00754
00755 default:
00756 if (sc != (pc&~QUOTE))
00757 return(0);
00758 }
00759 }
00760 return(*s == 0);
00761 }
00762
00763 static char *
00764 cclass(p, sub)
00765 register char *p;
00766 register int sub;
00767 {
00768 register int c, d, not, found;
00769
00770 if ((not = *p == NOT) != 0)
00771 p++;
00772 found = not;
00773 do {
00774 if (*p == '\0')
00775 return((char *)NULL);
00776 c = *p & CMASK;
00777 if (p[1] == '-' && p[2] != ']') {
00778 d = p[2] & CMASK;
00779 p++;
00780 } else
00781 d = c;
00782 if (c == sub || (c <= sub && sub <= d))
00783 found = !not;
00784 } while (*++p != ']');
00785 return(found? p+1: (char *)NULL);
00786 }
00787
00788
00789 #define REGSIZE sizeof(struct region)
00790 #define GROWBY 256
00791 #undef SHRINKBY 64
00792 #define FREE 32767
00793 #define BUSY 0
00794 #define ALIGN (sizeof(int)-1)
00795
00796
00797
00798 struct region {
00799 struct region *next;
00800 int area;
00801 };
00802
00803
00804
00805
00806
00807
00808 static struct region *areabot;
00809 static struct region *areatop;
00810 static struct region *areanxt;
00811
00812 void
00813 initarea()
00814 {
00815 while ((int)sbrk(0) & ALIGN)
00816 sbrk(1);
00817 areabot = (struct region *)sbrk(REGSIZE);
00818 areabot->next = areabot;
00819 areabot->area = BUSY;
00820 areatop = areabot;
00821 areanxt = areabot;
00822 }
00823
00824 char *
00825 getcell(nbytes)
00826 unsigned nbytes;
00827 {
00828 register int nregio;
00829 register struct region *p, *q;
00830 register i;
00831
00832 if (nbytes == 0)
00833 abort();
00834
00835
00836
00837 nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
00838 for (p = areanxt;;) {
00839 if (p->area > areanum) {
00840
00841
00842
00843 while ((q = p->next)->area > areanum && q != areanxt)
00844 p->next = q->next;
00845
00846
00847
00848 if (q >= p + nregio)
00849 goto found;
00850 }
00851 p = p->next;
00852 if (p == areanxt)
00853 break;
00854 }
00855 i = nregio >= GROWBY ? nregio : GROWBY;
00856 p = (struct region *)sbrk(i * REGSIZE);
00857 if (p == (struct region *)-1)
00858 return((char *)NULL);
00859 p--;
00860 if (p != areatop)
00861 abort();
00862 q = p + i;
00863 p->next = q;
00864 p->area = FREE;
00865 q->next = areabot;
00866 q->area = BUSY;
00867 areatop = q;
00868 found:
00869
00870
00871
00872 areanxt = p + nregio;
00873 if (areanxt < q) {
00874
00875
00876
00877 if (areanxt+1 > q)
00878 abort();
00879 areanxt->next = q;
00880 areanxt->area = FREE;
00881 p->next = areanxt;
00882 }
00883 p->area = areanum;
00884 return((char *)(p+1));
00885 }
00886
00887 void
00888 freecell(cp)
00889 char *cp;
00890 {
00891 register struct region *p;
00892
00893 if ((p = (struct region *)cp) != NULL) {
00894 p--;
00895 if (p < areanxt)
00896 areanxt = p;
00897 p->area = FREE;
00898 }
00899 }
00900
00901 void
00902 freearea(a)
00903 register int a;
00904 {
00905 register struct region *p, *top;
00906
00907 top = areatop;
00908 for (p = areabot; p != top; p = p->next)
00909 if (p->area >= a)
00910 p->area = FREE;
00911 }
00912
00913 void
00914 setarea(cp,a)
00915 char *cp;
00916 int a;
00917 {
00918 register struct region *p;
00919
00920 if ((p = (struct region *)cp) != NULL)
00921 (p-1)->area = a;
00922 }
00923
00924 int
00925 getarea(cp)
00926 char *cp;
00927 {
00928 return ((struct region*)cp-1)->area;
00929 }
00930
00931 void
00932 garbage()
00933 {
00934 register struct region *p, *q, *top;
00935
00936 top = areatop;
00937 for (p = areabot; p != top; p = p->next) {
00938 if (p->area > areanum) {
00939 while ((q = p->next)->area > areanum)
00940 p->next = q->next;
00941 areanxt = p;
00942 }
00943 }
00944 #ifdef SHRINKBY
00945 if (areatop >= q + SHRINKBY && q->area > areanum) {
00946 brk((char *)(q+1));
00947 q->next = areabot;
00948 q->area = BUSY;
00949 areatop = q;
00950 }
00951 #endif
00952 }