+#
+/*
+ * copyright 1973 bell telephone laboratories inc.
+ */
+
+#define intr 2
+#define quit 3
+#define linesiz 1000
+#define argsiz 50
+#define tresiz 100
+
+#define quote 0200
+#define fand 1
+#define fcat 2
+#define fpin 4
+#define fpou 8
+#define fpar 16
+#define fint 32
+#define tcom 1
+#define tpar 2
+#define tfil 3
+#define tlst 4
+#define dtyp 0
+#define dlef 1
+#define drit 2
+#define dflg 3
+#define dspr 4
+#define dcom 5
+#define ENOEXEC 8
+
+char *dolp;
+char **dolv;
+int dolc;
+char *promp;
+char *linep;
+char *elinep;
+char **argp;
+char **eargp;
+int *treep;
+int *treeend;
+char peekc;
+char gflg;
+char error;
+char acctf;
+char uid;
+char setintr;
+char *arginp;
+int onelflg;
+
+char *mesg[] {
+ 0,
+ "Hangup",
+ 0,
+ "Quit",
+ "Illegal instruction",
+ "Trace/BPT trap",
+ "IOT trap",
+ "EMT trap",
+ "Floating exception",
+ "Killed",
+ "Bus error",
+ "Memory fault",
+ "Bad system call"
+};
+
+struct stime {
+ int proct[2];
+ int cputim[2];
+ int systim[2];
+} timeb;
+
+main(c, av)
+int c;
+char **av;
+{
+ register f;
+ register char *acname, **v;
+
+ close(2);
+ if((f=dup(1)) != 2)
+ close(f);
+ v = av;
+ acname = "/usr/adm/sh_acct";
+ promp = "% ";
+ if(((uid = getuid())&0377) == 0) {
+ promp = "# ";
+ acname = "/usr/adm/su_acct";
+ }
+ acctf = open(acname, 1);
+ if(c > 1) {
+ promp = 0;
+ for (f=3; f<=15; f++)
+ close(f);
+ if (*v[1]=='-') {
+ **v = '-';
+ if (v[1][1]=='c' && c>2)
+ arginp = v[2];
+ else if (v[1][1]=='t')
+ onelflg = 2;
+ } else {
+ close(0);
+ f = open(v[1], 0);
+ if(f < 0) {
+ prs(v[1]);
+ err(": cannot open");
+ }
+ }
+ }
+ if(**v == '-') {
+ setintr++;
+ signal(quit, 1);
+ signal(intr, 1);
+ }
+ dolv = v+1;
+ dolc = c-1;
+
+loop:
+ if(promp != 0)
+ prs(promp);
+ peekc = getc();
+ main1();
+ goto loop;
+}
+
+main1()
+{
+ char line[linesiz];
+ char *args[argsiz];
+ int trebuf[tresiz];
+ register char c, *cp;
+ register *t;
+
+ argp = args;
+ eargp = args+argsiz-5;
+ linep = line;
+ elinep = line+linesiz-5;
+ error = 0;
+ gflg = 0;
+ do {
+ cp = linep;
+ word();
+ } while(*cp != '\n');
+ treep = trebuf;
+ treeend = &trebuf[tresiz];
+ if(gflg == 0) {
+ if(error == 0) {
+ setexit();
+ if (error)
+ return;
+ t = syntax(args, argp);
+ }
+ if(error != 0)
+ err("syntax error"); else
+ execute(t);
+ }
+}
+
+word()
+{
+ register char c, c1;
+
+ *argp++ = linep;
+
+loop:
+ switch(c = getc()) {
+
+ case ' ':
+ case '\t':
+ goto loop;
+
+ case '\'':
+ case '"':
+ c1 = c;
+ while((c=readc()) != c1) {
+ if(c == '\n') {
+ error++;
+ peekc = c;
+ return;
+ }
+ *linep++ = c|quote;
+ }
+ goto pack;
+
+ case '&':
+ case ';':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '|':
+ case '^':
+ case '\n':
+ *linep++ = c;
+ *linep++ = '\0';
+ return;
+ }
+
+ peekc = c;
+
+pack:
+ for(;;) {
+ c = getc();
+ if(any(c, " '\"\t;&<>()|^\n")) {
+ peekc = c;
+ if(any(c, "\"'"))
+ goto loop;
+ *linep++ = '\0';
+ return;
+ }
+ *linep++ = c;
+ }
+}
+
+tree(n)
+int n;
+{
+ register *t;
+
+ t = treep;
+ treep =+ n;
+ if (treep>treeend) {
+ prs("Command line overflow\n");
+ error++;
+ reset();
+ }
+ return(t);
+}
+
+getc()
+{
+ register char c;
+
+ if(peekc) {
+ c = peekc;
+ peekc = 0;
+ return(c);
+ }
+ if(argp > eargp) {
+ argp =- 10;
+ while((c=getc()) != '\n');
+ argp =+ 10;
+ err("Too many args");
+ gflg++;
+ return(c);
+ }
+ if(linep > elinep) {
+ linep =- 10;
+ while((c=getc()) != '\n');
+ linep =+ 10;
+ err("Too many characters");
+ gflg++;
+ return(c);
+ }
+getd:
+ if(dolp) {
+ c = *dolp++;
+ if(c != '\0')
+ return(c);
+ dolp = 0;
+ }
+ c = readc();
+ if(c == '\\') {
+ c = readc();
+ if(c == '\n')
+ return(' ');
+ return(c|quote);
+ }
+ if(c == '$') {
+ c = getc();
+ if(c>='0' && c<='9') {
+ if(c-'0' < dolc)
+ dolp = dolv[c-'0'];
+ goto getd;
+ }
+ }
+ return(c&0177);
+}
+
+readc()
+{
+ char cc;
+ register c;
+
+ if (arginp) {
+ if (arginp == 1)
+ exit();
+ if ((c = *arginp++) == 0) {
+ arginp = 1;
+ c = '\n';
+ }
+ return(c);
+ }
+ if (onelflg==1)
+ exit();
+ if(read(0, &cc, 1) != 1)
+ exit();
+ if (cc=='\n' && onelflg)
+ onelflg--;
+ return(cc);
+}
+
+/*
+ * syntax
+ * empty
+ * syn1
+ */
+
+syntax(p1, p2)
+char **p1, **p2;
+{
+
+ while(p1 != p2) {
+ if(any(**p1, ";&\n"))
+ p1++; else
+ return(syn1(p1, p2));
+ }
+ return(0);
+}
+
+/*
+ * syn1
+ * syn2
+ * syn2 & syntax
+ * syn2 ; syntax
+ */
+
+syn1(p1, p2)
+char **p1, **p2;
+{
+ register char **p;
+ register *t, *t1;
+ int l;
+
+ l = 0;
+ for(p=p1; p!=p2; p++)
+ switch(**p) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ if(l < 0)
+ error++;
+ continue;
+
+ case '&':
+ case ';':
+ case '\n':
+ if(l == 0) {
+ t = tree(4);
+ t[dtyp] = tlst;
+ t[dlef] = syn2(p1, p);
+ t[dflg] = 0;
+ if(**p == '&') {
+ t1 = t[dlef];
+ t1[dflg] =| fand|fint;
+ }
+ t[drit] = syntax(p+1, p2);
+ return(t);
+ }
+ }
+ if(l == 0)
+ return(syn2(p1, p2));
+ error++;
+}
+
+/*
+ * syn2
+ * syn3
+ * syn3 | syn2
+ */
+
+syn2(p1, p2)
+char **p1, **p2;
+{
+ register char **p;
+ register int l, *t;
+
+ l = 0;
+ for(p=p1; p!=p2; p++)
+ switch(**p) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ continue;
+
+ case '|':
+ case '^':
+ if(l == 0) {
+ t = tree(4);
+ t[dtyp] = tfil;
+ t[dlef] = syn3(p1, p);
+ t[drit] = syn2(p+1, p2);
+ t[dflg] = 0;
+ return(t);
+ }
+ }
+ return(syn3(p1, p2));
+}
+
+/*
+ * syn3
+ * ( syn1 ) [ < in ] [ > out ]
+ * word word* [ < in ] [ > out ]
+ */
+
+syn3(p1, p2)
+char **p1, **p2;
+{
+ register char **p;
+ char **lp, **rp;
+ register *t;
+ int b[100], n, l, i, o, c, flg;
+
+ flg = 0;
+ if(**p2 == ')')
+ flg =| fpar;
+ lp = 0;
+ rp = 0;
+ i = 0;
+ o = 0;
+ n = 0;
+ l = 0;
+ for(p=p1; p!=p2; p++)
+ switch(c = **p) {
+
+ case '(':
+ if(l == 0) {
+ if(lp != 0)
+ error++;
+ lp = p+1;
+ }
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ if(l == 0)
+ rp = p;
+ continue;
+
+ case '>':
+ p++;
+ if(p!=p2 && **p=='>')
+ flg =| fcat; else
+ p--;
+
+ case '<':
+ if(l == 0) {
+ p++;
+ if(p == p2) {
+ error++;
+ p--;
+ }
+ if(any(**p, "<>("))
+ error++;
+ if(c == '<') {
+ if(i != 0)
+ error++;
+ i = *p;
+ continue;
+ }
+ if(o != 0)
+ error++;
+ o = *p;
+ }
+ continue;
+
+ default:
+ if(l == 0)
+ b[n++] = *p;
+ }
+ if(lp != 0) {
+ if(n != 0)
+ error++;
+ t = tree(5);
+ t[dtyp] = tpar;
+ t[dspr] = syn1(lp, rp);
+ goto out;
+ }
+ if(n == 0)
+ error++;
+ b[n++] = 0;
+ t = tree(n+5);
+ t[dtyp] = tcom;
+ for(l=0; l<n; l++)
+ t[l+dcom] = b[l];
+out:
+ t[dflg] = flg;
+ t[dlef] = i;
+ t[drit] = o;
+ return(t);
+}
+
+scan(at, f)
+int *at;
+int (*f)();
+{
+ register char *p, c;
+ register *t;
+
+ t = at+dcom;
+ while(p = *t++)
+ while(c = *p)
+ *p++ = (*f)(c);
+}
+
+tglob(c)
+int c;
+{
+
+ if(any(c, "[?*"))
+ gflg = 1;
+ return(c);
+}
+
+trim(c)
+int c;
+{
+
+ return(c&0177);
+}
+
+execute(t, pf1, pf2)
+int *t, *pf1, *pf2;
+{
+ int i, f, pv[2];
+ register *t1;
+ register char *cp1, *cp2;
+ extern errno;
+
+ if(t != 0)
+ switch(t[dtyp]) {
+
+ case tcom:
+ cp1 = t[dcom];
+ if(equal(cp1, "chdir")) {
+ if(t[dcom+1] != 0) {
+ if(chdir(t[dcom+1]) < 0)
+ err("chdir: bad directory");
+ } else
+ err("chdir: arg count");
+ return;
+ }
+ if(equal(cp1, "shift")) {
+ if(dolc < 1) {
+ prs("shift: no args\n");
+ return;
+ }
+ dolv[1] = dolv[0];
+ dolv++;
+ dolc--;
+ return;
+ }
+ if(equal(cp1, "login")) {
+ if(promp != 0) {
+ close(acctf);
+ execv("/bin/login", t+dcom);
+ }
+ prs("login: cannot execute\n");
+ return;
+ }
+ if(equal(cp1, "wait")) {
+ pwait(-1, 0);
+ return;
+ }
+ if(equal(cp1, ":"))
+ return;
+
+ case tpar:
+ f = t[dflg];
+ i = 0;
+ if((f&fpar) == 0)
+ i = fork();
+ if(i == -1) {
+ err("try again");
+ return;
+ }
+ if(i != 0) {
+ if((f&fpin) != 0) {
+ close(pf1[0]);
+ close(pf1[1]);
+ }
+ if((f&fand) != 0) {
+ prn(i);
+ prs("\n");
+ return;
+ }
+ if((f&fpou) == 0)
+ pwait(i, t);
+ return;
+ }
+ if(t[dlef] != 0) {
+ close(0);
+ i = open(t[dlef], 0);
+ if(i < 0) {
+ prs(t[dlef]);
+ err(": cannot open");
+ exit();
+ }
+ }
+ if(t[drit] != 0) {
+ if((f&fcat) != 0) {
+ i = open(t[drit], 1);
+ if(i >= 0) {
+ seek(i, 0, 2);
+ goto f1;
+ }
+ }
+ i = creat(t[drit], 0666);
+ if(i < 0) {
+ prs(t[drit]);
+ err(": cannot create");
+ exit();
+ }
+ f1:
+ close(1);
+ dup(i);
+ close(i);
+ }
+ if((f&fpin) != 0) {
+ close(0);
+ dup(pf1[0]);
+ close(pf1[0]);
+ close(pf1[1]);
+ }
+ if((f&fpou) != 0) {
+ close(1);
+ dup(pf2[1]);
+ close(pf2[0]);
+ close(pf2[1]);
+ }
+ if((f&fint)!=0 && t[dlef]==0 && (f&fpin)==0) {
+ close(0);
+ open("/dev/null", 0);
+ }
+ if((f&fint) == 0 && setintr) {
+ signal(intr, 0);
+ signal(quit, 0);
+ }
+ if(t[dtyp] == tpar) {
+ if(t1 = t[dspr])
+ t1[dflg] =| f&fint;
+ execute(t1);
+ exit();
+ }
+ close(acctf);
+ gflg = 0;
+ scan(t, &tglob);
+ if(gflg) {
+ t[dspr] = "/etc/glob";
+ execv(t[dspr], t+dspr);
+ prs("glob: cannot execute\n");
+ exit();
+ }
+ scan(t, &trim);
+ *linep = 0;
+ execv(t[dcom], t+dcom);
+ if (errno==ENOEXEC)
+ goto runcom;
+ cp1 = linep;
+ cp2 = "/usr/bin/";
+ while(*cp1 = *cp2++)
+ cp1++;
+ cp2 = t[dcom];
+ while(*cp1++ = *cp2++);
+ execv(linep+4, t+dcom);
+ if (errno==ENOEXEC)
+ goto runcom;
+ execv(linep, t+dcom);
+ if (errno==ENOEXEC)
+ goto runcom;
+ prs(t[dcom]);
+ err(": not found");
+ exit();
+ runcom:
+ if (*linep)
+ t[dcom] = linep;
+ t[dspr] = "/bin/sh";
+ execv(t[dspr], t+dspr);
+ prs("No shell!\n");
+ exit();
+
+ case tfil:
+ f = t[dflg];
+ pipe(pv);
+ t1 = t[dlef];
+ t1[dflg] =| fpou | (f&(fpin|fint));
+ execute(t1, pf1, pv);
+ t1 = t[drit];
+ t1[dflg] =| fpin | (f&(fpou|fint|fand));
+ execute(t1, pv, pf2);
+ return;
+
+ case tlst:
+ f = t[dflg]&fint;
+ if(t1 = t[dlef])
+ t1[dflg] =| f;
+ execute(t1);
+ if(t1 = t[drit])
+ t1[dflg] =| f;
+ execute(t1);
+ return;
+
+ }
+}
+
+err(s)
+char *s;
+{
+
+ prs(s);
+ prs("\n");
+ if(promp == 0) {
+ seek(0, 0, 2);
+ exit();
+ }
+}
+
+prs(as)
+char *as;
+{
+ register char *s;
+
+ s = as;
+ while(*s)
+ putc(*s++);
+}
+
+putc(c)
+{
+
+ write(2, &c, 1);
+}
+
+prn(n)
+int n;
+{
+ register a;
+
+ if(a=ldiv(0,n,10))
+ prn(a);
+ putc(lrem(0,n,10)+'0');
+}
+
+any(c, as)
+int c;
+char *as;
+{
+ register char *s;
+
+ s = as;
+ while(*s)
+ if(*s++ == c)
+ return(1);
+ return(0);
+}
+
+equal(as1, as2)
+char *as1, *as2;
+{
+ register char *s1, *s2;
+
+ s1 = as1;
+ s2 = as2;
+ while(*s1++ == *s2)
+ if(*s2++ == '\0')
+ return(1);
+ return(0);
+}
+
+pwait(i, t)
+int i, *t;
+{
+ register p, e;
+ int s;
+
+ if(i != 0)
+ for(;;) {
+ times(&timeb);
+ time(timeb.proct);
+ p = wait(&s);
+ if(p == -1)
+ break;
+ e = s&0177;
+ if(mesg[e] != 0) {
+ if(p != i) {
+ prn(p);
+ prs(": ");
+ }
+ prs(mesg[e]);
+ if(s&0200)
+ prs(" -- Core dumped");
+ }
+ if(e != 0)
+ err("");
+ if(i == p) {
+ acct(t);
+ break;
+ } else
+ acct(0);
+ }
+}
+
+acct(t)
+int *t;
+{
+ if(t == 0)
+ enacct("**gok"); else
+ if(*t == tpar)
+ enacct("()"); else
+ enacct(t[dcom]);
+}
+
+enacct(as)
+char *as;
+{
+ struct stime timbuf;
+ struct {
+ char cname[14];
+ char fill;
+ char uid;
+ int datet[2];
+ int realt[2];
+ int bcput[2];
+ int bsyst[2];
+ } tbuf;
+ register i;
+ register char *np, *s;
+
+ s = as;
+ times(&timbuf);
+ time(timbuf.proct);
+ lsub(tbuf.realt, timbuf.proct, timeb.proct);
+ lsub(tbuf.bcput, timbuf.cputim, timeb.cputim);
+ lsub(tbuf.bsyst, timbuf.systim, timeb.systim);
+ do {
+ np = s;
+ while (*s != '\0' && *s != '/')
+ s++;
+ } while (*s++ != '\0');
+ for (i=0; i<14; i++) {
+ tbuf.cname[i] = *np;
+ if (*np)
+ np++;
+ }
+ tbuf.datet[0] = timbuf.proct[0];
+ tbuf.datet[1] = timbuf.proct[1];
+ tbuf.uid = uid;
+ seek(acctf, 0, 2);
+ write(acctf, &tbuf, sizeof(tbuf));
+}