899 lines
11 KiB
C
899 lines
11 KiB
C
#
|
|
/*
|
|
*/
|
|
|
|
#define INTR 2
|
|
#define QUIT 3
|
|
#define LINSIZ 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 FPRS 64
|
|
#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 ENOMEM 12
|
|
#define ENOEXEC 8
|
|
|
|
char *dolp;
|
|
char pidp[6];
|
|
int ldivr;
|
|
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",
|
|
0,
|
|
"Sig 14",
|
|
"Sig 15",
|
|
"Sig 16",
|
|
"Sig 17",
|
|
"Sig 18",
|
|
"Sig 19",
|
|
};
|
|
|
|
struct stime {
|
|
int proct[2];
|
|
int cputim[2];
|
|
int systim[2];
|
|
} timeb;
|
|
|
|
char line[LINSIZ];
|
|
char *args[ARGSIZ];
|
|
int trebuf[TRESIZ];
|
|
|
|
main(c, av)
|
|
int c;
|
|
char **av;
|
|
{
|
|
register f;
|
|
register char *acname, **v;
|
|
|
|
for(f=2; f<15; f++)
|
|
close(f);
|
|
if((f=dup(1)) != 2)
|
|
close(f);
|
|
dolc = getpid();
|
|
for(f=4; f>=0; f--) {
|
|
dolc = ldiv(0, dolc, 10);
|
|
pidp[f] = ldivr+'0';
|
|
}
|
|
v = av;
|
|
acname = "/usr/adm/sha";
|
|
promp = "% ";
|
|
if(((uid = getuid())&0377) == 0)
|
|
promp = "# ";
|
|
acctf = open(acname, 1);
|
|
if(c > 1) {
|
|
promp = 0;
|
|
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()
|
|
{
|
|
register char c, *cp;
|
|
register *t;
|
|
|
|
argp = args;
|
|
eargp = args+ARGSIZ-5;
|
|
linep = line;
|
|
elinep = line+LINSIZ-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 = readc();
|
|
if(c>='0' && c<='9') {
|
|
if(c-'0' < dolc)
|
|
dolp = dolv[c-'0'];
|
|
goto getd;
|
|
}
|
|
if(c == '$') {
|
|
dolp = pidp;
|
|
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) {
|
|
l = **p;
|
|
t = tree(4);
|
|
t[DTYP] = TLST;
|
|
t[DLEF] = syn2(p1, p);
|
|
t[DFLG] = 0;
|
|
if(l == '&') {
|
|
t1 = t[DLEF];
|
|
t1[DFLG] =| FAND|FPRS|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 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)
|
|
p1[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++;
|
|
p1[n++] = 0;
|
|
t = tree(n+5);
|
|
t[DTYP] = TCOM;
|
|
for(l=0; l<n; l++)
|
|
t[l+DCOM] = p1[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, "newgrp")) {
|
|
if(promp != 0) {
|
|
close(acctf);
|
|
execv("/bin/newgrp", t+DCOM);
|
|
}
|
|
prs("newgrp: 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&FPRS) != 0) {
|
|
prn(i);
|
|
prs("\n");
|
|
}
|
|
if((f&FAND) != 0)
|
|
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;
|
|
texec(t[DCOM], t);
|
|
cp1 = linep;
|
|
cp2 = "/usr/bin/";
|
|
while(*cp1 = *cp2++)
|
|
cp1++;
|
|
cp2 = t[DCOM];
|
|
while(*cp1++ = *cp2++);
|
|
texec(linep+4, t);
|
|
texec(linep, t);
|
|
prs(t[DCOM]);
|
|
err(": not found");
|
|
exit();
|
|
|
|
case TFIL:
|
|
f = t[DFLG];
|
|
pipe(pv);
|
|
t1 = t[DLEF];
|
|
t1[DFLG] =| FPOU | (f&(FPIN|FINT|FPRS));
|
|
execute(t1, pf1, pv);
|
|
t1 = t[DRIT];
|
|
t1[DFLG] =| FPIN | (f&(FPOU|FINT|FAND|FPRS));
|
|
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;
|
|
|
|
}
|
|
}
|
|
|
|
texec(f, at)
|
|
int *at;
|
|
{
|
|
extern errno;
|
|
register int *t;
|
|
|
|
t = at;
|
|
execv(f, t+DCOM);
|
|
if (errno==ENOEXEC) {
|
|
if (*linep)
|
|
t[DCOM] = linep;
|
|
t[DSPR] = "/bin/sh";
|
|
execv(t[DSPR], t+DSPR);
|
|
prs("No shell!\n");
|
|
exit();
|
|
}
|
|
if (errno==ENOMEM) {
|
|
prs(t[DCOM]);
|
|
err(": too large");
|
|
exit();
|
|
}
|
|
}
|
|
|
|
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 shf;
|
|
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;
|
|
tbuf.shf = 0;
|
|
if (promp==0)
|
|
tbuf.shf = 1;
|
|
seek(acctf, 0, 2);
|
|
write(acctf, &tbuf, sizeof(tbuf));
|
|
}
|