Research V7 development
[unix-history] / usr / src / cmd / osh.c
CommitLineData
88f62f26
KT
1/*
2 */
3
4#include <setjmp.h>
5#define INTR 2
6#define QUIT 3
7#define LINSIZ 1000
8#define ARGSIZ 50
9#define TRESIZ 100
10
11#define QUOTE 0200
12#define FAND 1
13#define FCAT 2
14#define FPIN 4
15#define FPOU 8
16#define FPAR 16
17#define FINT 32
18#define FPRS 64
19#define TCOM 1
20#define TPAR 2
21#define TFIL 3
22#define TLST 4
23#define DTYP 0
24#define DLEF 1
25#define DRIT 2
26#define DFLG 3
27#define DSPR 4
28#define DCOM 5
29#define ENOMEM 12
30#define ENOEXEC 8
31
32int errval;
33char *dolp;
34char pidp[6];
35char **dolv;
36jmp_buf jmpbuf;
37int dolc;
38char *promp;
39char *linep;
40char *elinep;
41char **argp;
42char **eargp;
43int *treep;
44int *treeend;
45char peekc;
46char gflg;
47char error;
48char uid;
49char setintr;
50char *arginp;
51int onelflg;
52int stoperr;
53
54#define NSIG 16
55char *mesg[NSIG] {
56 0,
57 "Hangup",
58 0,
59 "Quit",
60 "Illegal instruction",
61 "Trace/BPT trap",
62 "IOT trap",
63 "EMT trap",
64 "Floating exception",
65 "Killed",
66 "Bus error",
67 "Memory fault",
68 "Bad system call",
69 0,
70 "Alarm clock",
71 "Terminated",
72};
73
74char line[LINSIZ];
75char *args[ARGSIZ];
76int trebuf[TRESIZ];
77
78main(c, av)
79int c;
80char **av;
81{
82 register f;
83 register char *acname, **v;
84
85 for(f=3; f<15; f++)
86 close(f);
87 dolc = getpid();
88 for(f=4; f>=0; f--) {
89 dolc = dolc/10;
90 pidp[f] = dolc%10 + '0';
91 }
92 v = av;
93 acname = "<none>";
94 promp = "% ";
95 if((uid = getuid()) == 0)
96 promp = "# ";
97 if(c>1 && v[1][0]=='-' && v[1][1]=='e') {
98 ++stoperr;
99 v[1] = v[0];
100 ++v;
101 --c;
102 }
103 if(c > 1) {
104 promp = 0;
105 if (*v[1]=='-') {
106 **v = '-';
107 if (v[1][1]=='c' && c>2)
108 arginp = v[2];
109 else if (v[1][1]=='t')
110 onelflg = 2;
111 } else {
112 close(0);
113 f = open(v[1], 0);
114 if(f < 0) {
115 prs(v[1]);
116 err(": cannot open",255);
117 }
118 }
119 }
120 if(**v == '-') {
121 signal(QUIT, 1);
122 f = signal(INTR, 1);
123 if ((arginp==0&&onelflg==0) || (f&01)==0)
124 setintr++;
125 }
126 dolv = v+1;
127 dolc = c-1;
128
129loop:
130 if(promp != 0)
131 prs(promp);
132 peekc = getc();
133 main1();
134 goto loop;
135}
136
137main1()
138{
139 register char *cp;
140 register *t;
141
142 argp = args;
143 eargp = args+ARGSIZ-5;
144 linep = line;
145 elinep = line+LINSIZ-5;
146 error = 0;
147 gflg = 0;
148 do {
149 cp = linep;
150 word();
151 } while(*cp != '\n');
152 treep = trebuf;
153 treeend = &trebuf[TRESIZ];
154 if(gflg == 0) {
155 if(error == 0) {
156 setjmp(jmpbuf);
157 if (error)
158 return;
159 t = syntax(args, argp);
160 }
161 if(error != 0)
162 err("syntax error",255); else
163 execute(t);
164 }
165}
166
167word()
168{
169 register char c, c1;
170
171 *argp++ = linep;
172
173loop:
174 switch(c = getc()) {
175
176 case ' ':
177 case '\t':
178 goto loop;
179
180 case '\'':
181 case '"':
182 c1 = c;
183 while((c=readc()) != c1) {
184 if(c == '\n') {
185 error++;
186 peekc = c;
187 return;
188 }
189 *linep++ = c|QUOTE;
190 }
191 goto pack;
192
193 case '&':
194 case ';':
195 case '<':
196 case '>':
197 case '(':
198 case ')':
199 case '|':
200 case '^':
201 case '\n':
202 *linep++ = c;
203 *linep++ = '\0';
204 return;
205 }
206
207 peekc = c;
208
209pack:
210 for(;;) {
211 c = getc();
212 if(any(c, " '\"\t;&<>()|^\n")) {
213 peekc = c;
214 if(any(c, "\"'"))
215 goto loop;
216 *linep++ = '\0';
217 return;
218 }
219 *linep++ = c;
220 }
221}
222
223tree(n)
224int n;
225{
226 register *t;
227
228 t = treep;
229 treep =+ n;
230 if (treep>treeend) {
231 prs("Command line overflow\n");
232 error++;
233 longjmp(jmpbuf, 1);
234 }
235 return(t);
236}
237
238getc()
239{
240 register char c;
241
242 if(peekc) {
243 c = peekc;
244 peekc = 0;
245 return(c);
246 }
247 if(argp > eargp) {
248 argp =- 10;
249 while((c=getc()) != '\n');
250 argp =+ 10;
251 err("Too many args",255);
252 gflg++;
253 return(c);
254 }
255 if(linep > elinep) {
256 linep =- 10;
257 while((c=getc()) != '\n');
258 linep =+ 10;
259 err("Too many characters",255);
260 gflg++;
261 return(c);
262 }
263getd:
264 if(dolp) {
265 c = *dolp++;
266 if(c != '\0')
267 return(c);
268 dolp = 0;
269 }
270 c = readc();
271 if(c == '\\') {
272 c = readc();
273 if(c == '\n')
274 return(' ');
275 return(c|QUOTE);
276 }
277 if(c == '$') {
278 c = readc();
279 if(c>='0' && c<='9') {
280 if(c-'0' < dolc)
281 dolp = dolv[c-'0'];
282 goto getd;
283 }
284 if(c == '$') {
285 dolp = pidp;
286 goto getd;
287 }
288 }
289 return(c&0177);
290}
291
292readc()
293{
294 int rdstat;
295 char cc;
296 register c;
297
298 if (arginp) {
299 if (arginp == 1)
300 exit(errval);
301 if ((c = *arginp++) == 0) {
302 arginp = 1;
303 c = '\n';
304 }
305 return(c);
306 }
307 if (onelflg==1)
308 exit(255);
309 if((rdstat = read(0, &cc, 1)) != 1)
310 if(rdstat==0) exit(errval); /* end of file*/
311 else exit(255); /* error */
312 if (cc=='\n' && onelflg)
313 onelflg--;
314 return(cc);
315}
316
317/*
318 * syntax
319 * empty
320 * syn1
321 */
322
323syntax(p1, p2)
324char **p1, **p2;
325{
326
327 while(p1 != p2) {
328 if(any(**p1, ";&\n"))
329 p1++; else
330 return(syn1(p1, p2));
331 }
332 return(0);
333}
334
335/*
336 * syn1
337 * syn2
338 * syn2 & syntax
339 * syn2 ; syntax
340 */
341
342syn1(p1, p2)
343char **p1, **p2;
344{
345 register char **p;
346 register *t, *t1;
347 int l;
348
349 l = 0;
350 for(p=p1; p!=p2; p++)
351 switch(**p) {
352
353 case '(':
354 l++;
355 continue;
356
357 case ')':
358 l--;
359 if(l < 0)
360 error++;
361 continue;
362
363 case '&':
364 case ';':
365 case '\n':
366 if(l == 0) {
367 l = **p;
368 t = tree(4);
369 t[DTYP] = TLST;
370 t[DLEF] = syn2(p1, p);
371 t[DFLG] = 0;
372 if(l == '&') {
373 t1 = t[DLEF];
374 t1[DFLG] =| FAND|FPRS|FINT;
375 }
376 t[DRIT] = syntax(p+1, p2);
377 return(t);
378 }
379 }
380 if(l == 0)
381 return(syn2(p1, p2));
382 error++;
383 return(0);
384}
385
386/*
387 * syn2
388 * syn3
389 * syn3 | syn2
390 */
391
392syn2(p1, p2)
393char **p1, **p2;
394{
395 register char **p;
396 register int l, *t;
397
398 l = 0;
399 for(p=p1; p!=p2; p++)
400 switch(**p) {
401
402 case '(':
403 l++;
404 continue;
405
406 case ')':
407 l--;
408 continue;
409
410 case '|':
411 case '^':
412 if(l == 0) {
413 t = tree(4);
414 t[DTYP] = TFIL;
415 t[DLEF] = syn3(p1, p);
416 t[DRIT] = syn2(p+1, p2);
417 t[DFLG] = 0;
418 return(t);
419 }
420 }
421 return(syn3(p1, p2));
422}
423
424/*
425 * syn3
426 * ( syn1 ) [ < in ] [ > out ]
427 * word word* [ < in ] [ > out ]
428 */
429
430syn3(p1, p2)
431char **p1, **p2;
432{
433 register char **p;
434 char **lp, **rp;
435 register *t;
436 int n, l, i, o, c, flg;
437
438 flg = 0;
439 if(**p2 == ')')
440 flg =| FPAR;
441 lp = 0;
442 rp = 0;
443 i = 0;
444 o = 0;
445 n = 0;
446 l = 0;
447 for(p=p1; p!=p2; p++)
448 switch(c = **p) {
449
450 case '(':
451 if(l == 0) {
452 if(lp != 0)
453 error++;
454 lp = p+1;
455 }
456 l++;
457 continue;
458
459 case ')':
460 l--;
461 if(l == 0)
462 rp = p;
463 continue;
464
465 case '>':
466 p++;
467 if(p!=p2 && **p=='>')
468 flg =| FCAT; else
469 p--;
470
471 case '<':
472 if(l == 0) {
473 p++;
474 if(p == p2) {
475 error++;
476 p--;
477 }
478 if(any(**p, "<>("))
479 error++;
480 if(c == '<') {
481 if(i != 0)
482 error++;
483 i = *p;
484 continue;
485 }
486 if(o != 0)
487 error++;
488 o = *p;
489 }
490 continue;
491
492 default:
493 if(l == 0)
494 p1[n++] = *p;
495 }
496 if(lp != 0) {
497 if(n != 0)
498 error++;
499 t = tree(5);
500 t[DTYP] = TPAR;
501 t[DSPR] = syn1(lp, rp);
502 goto out;
503 }
504 if(n == 0)
505 error++;
506 p1[n++] = 0;
507 t = tree(n+5);
508 t[DTYP] = TCOM;
509 for(l=0; l<n; l++)
510 t[l+DCOM] = p1[l];
511out:
512 t[DFLG] = flg;
513 t[DLEF] = i;
514 t[DRIT] = o;
515 return(t);
516}
517
518scan(at, f)
519int *at;
520int (*f)();
521{
522 register char *p, c;
523 register *t;
524
525 t = at+DCOM;
526 while(p = *t++)
527 while(c = *p)
528 *p++ = (*f)(c);
529}
530
531tglob(c)
532int c;
533{
534
535 if(any(c, "[?*"))
536 gflg = 1;
537 return(c);
538}
539
540trim(c)
541int c;
542{
543
544 return(c&0177);
545}
546
547execute(t, pf1, pf2)
548int *t, *pf1, *pf2;
549{
550 int i, f, pv[2];
551 register *t1;
552 register char *cp1, *cp2;
553 extern errno;
554
555 if(t != 0)
556 switch(t[DTYP]) {
557
558 case TCOM:
559 cp1 = t[DCOM];
560 if(equal(cp1, "chdir")) {
561 if(t[DCOM+1] != 0) {
562 if(chdir(t[DCOM+1]) < 0)
563 err("chdir: bad directory",255);
564 } else
565 err("chdir: arg count",255);
566 return;
567 }
568 if(equal(cp1, "shift")) {
569 if(dolc < 1) {
570 prs("shift: no args\n");
571 return;
572 }
573 dolv[1] = dolv[0];
574 dolv++;
575 dolc--;
576 return;
577 }
578 if(equal(cp1, "login")) {
579 if(promp != 0) {
580 execv("/bin/login", t+DCOM);
581 }
582 prs("login: cannot execute\n");
583 return;
584 }
585 if(equal(cp1, "newgrp")) {
586 if(promp != 0) {
587 execv("/bin/newgrp", t+DCOM);
588 }
589 prs("newgrp: cannot execute\n");
590 return;
591 }
592 if(equal(cp1, "wait")) {
593 pwait(-1, 0);
594 return;
595 }
596 if(equal(cp1, ":"))
597 return;
598
599 case TPAR:
600 f = t[DFLG];
601 i = 0;
602 if((f&FPAR) == 0)
603 i = fork();
604 if(i == -1) {
605 err("try again",255);
606 return;
607 }
608 if(i != 0) {
609 if((f&FPIN) != 0) {
610 close(pf1[0]);
611 close(pf1[1]);
612 }
613 if((f&FPRS) != 0) {
614 prn(i);
615 prs("\n");
616 }
617 if((f&FAND) != 0)
618 return;
619 if((f&FPOU) == 0)
620 pwait(i, t);
621 return;
622 }
623 if(t[DLEF] != 0) {
624 close(0);
625 i = open(t[DLEF], 0);
626 if(i < 0) {
627 prs(t[DLEF]);
628 err(": cannot open",255);
629 exit(255);
630 }
631 }
632 if(t[DRIT] != 0) {
633 if((f&FCAT) != 0) {
634 i = open(t[DRIT], 1);
635 if(i >= 0) {
636 lseek(i, 0L, 2);
637 goto f1;
638 }
639 }
640 i = creat(t[DRIT], 0666);
641 if(i < 0) {
642 prs(t[DRIT]);
643 err(": cannot create",255);
644 exit(255);
645 }
646 f1:
647 close(1);
648 dup(i);
649 close(i);
650 }
651 if((f&FPIN) != 0) {
652 close(0);
653 dup(pf1[0]);
654 close(pf1[0]);
655 close(pf1[1]);
656 }
657 if((f&FPOU) != 0) {
658 close(1);
659 dup(pf2[1]);
660 close(pf2[0]);
661 close(pf2[1]);
662 }
663 if((f&FINT)!=0 && t[DLEF]==0 && (f&FPIN)==0) {
664 close(0);
665 open("/dev/null", 0);
666 }
667 if((f&FINT) == 0 && setintr) {
668 signal(INTR, 0);
669 signal(QUIT, 0);
670 }
671 if(t[DTYP] == TPAR) {
672 if(t1 = t[DSPR])
673 t1[DFLG] =| f&FINT;
674 execute(t1);
675 exit(255);
676 }
677 gflg = 0;
678 scan(t, tglob);
679 if(gflg) {
680 t[DSPR] = "/etc/glob";
681 execv(t[DSPR], t+DSPR);
682 prs("glob: cannot execute\n");
683 exit(255);
684 }
685 scan(t, trim);
686 *linep = 0;
687 texec(t[DCOM], t);
688 cp1 = linep;
689 cp2 = "/usr/bin/";
690 while(*cp1 = *cp2++)
691 cp1++;
692 cp2 = t[DCOM];
693 while(*cp1++ = *cp2++);
694 texec(linep+4, t);
695 texec(linep, t);
696 prs(t[DCOM]);
697 err(": not found",255);
698 exit(255);
699
700 case TFIL:
701 f = t[DFLG];
702 pipe(pv);
703 t1 = t[DLEF];
704 t1[DFLG] =| FPOU | (f&(FPIN|FINT|FPRS));
705 execute(t1, pf1, pv);
706 t1 = t[DRIT];
707 t1[DFLG] =| FPIN | (f&(FPOU|FINT|FAND|FPRS));
708 execute(t1, pv, pf2);
709 return;
710
711 case TLST:
712 f = t[DFLG]&FINT;
713 if(t1 = t[DLEF])
714 t1[DFLG] =| f;
715 execute(t1);
716 if(t1 = t[DRIT])
717 t1[DFLG] =| f;
718 execute(t1);
719 return;
720
721 }
722}
723
724texec(f, at)
725int *at;
726{
727 extern errno;
728 register int *t;
729
730 t = at;
731 execv(f, t+DCOM);
732 if (errno==ENOEXEC) {
733 if (*linep)
734 t[DCOM] = linep;
735 t[DSPR] = "/usr/bin/osh";
736 execv(t[DSPR], t+DSPR);
737 prs("No shell!\n");
738 exit(255);
739 }
740 if (errno==ENOMEM) {
741 prs(t[DCOM]);
742 err(": too large",255);
743 exit(255);
744 }
745}
746
747err(s, exitno)
748char *s;
749int exitno;
750{
751
752 prs(s);
753 prs("\n");
754 if(promp == 0) {
755 lseek(0, 0L, 2);
756 exit(exitno);
757 }
758}
759
760prs(as)
761char *as;
762{
763 register char *s;
764
765 s = as;
766 while(*s)
767 putc(*s++);
768}
769
770putc(c)
771{
772 char cc;
773
774 cc = c;
775 write(2, &cc, 1);
776}
777
778prn(n)
779int n;
780{
781 register a;
782
783 if (a = n/10)
784 prn(a);
785 putc(n%10 + '0');
786}
787
788any(c, as)
789int c;
790char *as;
791{
792 register char *s;
793
794 s = as;
795 while(*s)
796 if(*s++ == c)
797 return(1);
798 return(0);
799}
800
801equal(as1, as2)
802char *as1, *as2;
803{
804 register char *s1, *s2;
805
806 s1 = as1;
807 s2 = as2;
808 while(*s1++ == *s2)
809 if(*s2++ == '\0')
810 return(1);
811 return(0);
812}
813
814pwait(i, t)
815int i, *t;
816{
817 register p, e;
818 int s;
819
820 if(i != 0)
821 for(;;) {
822 p = wait(&s);
823 if(p == -1)
824 break;
825 e = s&0177;
826 if (e>=NSIG || mesg[e]) {
827 if(p != i) {
828 prn(p);
829 prs(": ");
830 }
831 if (e < NSIG)
832 prs(mesg[e]);
833 else {
834 prs("Signal ");
835 prn(e);
836 }
837 if(s&0200)
838 prs(" -- Core dumped");
839 }
840 if (e || s&&stoperr)
841 err("", (s>>8)|e );
842 errval =| (s>>8);
843 }
844}