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
15 int intr;
16 int inparse;
17 char flags['z'-'a'+1];
18 char *flag = flags-'a';
19 char *elinep = line+sizeof(line)-5;
20 char *null = "";
21 int heedint =1;
22 struct env e ={line, iostack, iostack-1,
23 (xint *)NULL, FDBASE, (struct env *)NULL};
24
25 extern char **environ; /* environment pointer */
26
27 /*
28 * default shell, search rules
29 */
30 char shellname[] = "/bin/sh";
31 char 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
main(argc,argv)41 int main(argc, argv)
42 int argc;
43 register 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
184 void
setdash()185 setdash()
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
198 int
newfile(s)199 newfile(s)
200 register 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
217 void
onecommand()218 onecommand()
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
265 void
fail()266 fail()
267 {
268 longjmp(failpt, 1);
269 /* NOTREACHED */
270 }
271
272 void
leave()273 leave()
274 {
275 if (execflg)
276 fail();
277 scraphere();
278 freehere(1);
279 runtrap(0);
280 exit(exstat);
281 /* NOTREACHED */
282 }
283
284 void
warn(s)285 warn(s)
286 register char *s;
287 {
288 if(*s) {
289 prs(s);
290 exstat = -1;
291 }
292 prs("\n");
293 if (flag['e'])
294 leave();
295 }
296
297 void
err(s)298 err(s)
299 char *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
312 int
newenv(f)313 newenv(f)
314 int 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
334 void
quitenv()335 quitenv()
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 */
353 int
anys(s1,s2)354 anys(s1, s2)
355 register 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 */
366 int
any(c,s)367 any(c, s)
368 register int c;
369 register char *s;
370 {
371 while (*s)
372 if (*s++ == c)
373 return(1);
374 return(0);
375 }
376
377 char *
putn(n)378 putn(n)
379 register int n;
380 {
381 return(itoa(n, -1));
382 }
383
384 char *
itoa(u,n)385 itoa(u, n)
386 register unsigned u;
387 int 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
409 void
next(f)410 next(f)
411 int f;
412 {
413 PUSHIO(afile, f, filechar);
414 }
415
416 void
onintr(s)417 onintr(s)
418 int 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
434 int
letter(c)435 letter(c)
436 register c;
437 {
438 return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
439 }
440
441 int
digit(c)442 digit(c)
443 register c;
444 {
445 return(c >= '0' && c <= '9');
446 }
447
448 int
letnum(c)449 letnum(c)
450 register c;
451 {
452 return(letter(c) || digit(c));
453 }
454
455 char *
space(n)456 space(n)
457 int n;
458 {
459 register char *cp;
460
461 if ((cp = getcell(n)) == 0)
462 err("out of string space");
463 return(cp);
464 }
465
466 char *
strsave(s,a)467 strsave(s, a)
468 register char *s;
469 int 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
482 void
xfree(s)483 xfree(s)
484 register char *s;
485 {
486 DELETE(s);
487 }
488
489 /*
490 * trap handling
491 */
492 void
sig(i)493 sig(i)
494 register int i;
495 {
496 trapset = i;
497 signal(i, sig);
498 }
499
runtrap(i)500 void runtrap(i)
501 int 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 */
521 struct var *
lookup(n)522 lookup(n)
523 register 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 */
564 void
setval(vp,val)565 setval(vp, val)
566 struct var *vp;
567 char *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 */
579 void
nameval(vp,val,name)580 nameval(vp, val, name)
581 register struct var *vp;
582 char *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
619 void
export(vp)620 export(vp)
621 struct var *vp;
622 {
623 vp->status |= EXPORT;
624 }
625
626 void
ronly(vp)627 ronly(vp)
628 struct var *vp;
629 {
630 if (letter(vp->name[0])) /* not an internal symbol ($# etc) */
631 vp->status |= RONLY;
632 }
633
634 int
isassign(s)635 isassign(s)
636 register 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
646 int
assign(s,cf)647 assign(s, cf)
648 register char *s;
649 int 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
666 int
checkname(cp)667 checkname(cp)
668 register 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
678 void
putvlist(f,out)679 putvlist(f, out)
680 register 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
695 int
eqname(n1,n2)696 eqname(n1, n2)
697 register char *n1, *n2;
698 {
699 for (; *n1 != '=' && *n1 != 0; n1++)
700 if (*n2++ != *n1)
701 return(0);
702 return(*n2 == 0 || *n2 == '=');
703 }
704
705 static char *
findeq(cp)706 findeq(cp)
707 register 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
727 int
gmatch(s,p)728 gmatch(s, p)
729 register 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
764 static char *
cclass(p,sub)765 cclass(p, sub)
766 register char *p;
767 register 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
799 struct 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 */
809 static struct region *areabot; /* bottom of area */
810 static struct region *areatop; /* top of area */
811 static struct region *areanxt; /* starting point of scan */
812
813 void
initarea()814 initarea()
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
825 char *
getcell(nbytes)826 getcell(nbytes)
827 unsigned 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;
869 found:
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
888 void
freecell(cp)889 freecell(cp)
890 char *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
902 void
freearea(a)903 freearea(a)
904 register 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
914 void
setarea(cp,a)915 setarea(cp,a)
916 char *cp;
917 int a;
918 {
919 register struct region *p;
920
921 if ((p = (struct region *)cp) != NULL)
922 (p-1)->area = a;
923 }
924
925 int
getarea(cp)926 getarea(cp)
927 char *cp;
928 {
929 return ((struct region*)cp-1)->area;
930 }
931
932 void
garbage()933 garbage()
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