/* * Maybe `simple' is a misnomer. */#include "rc.h"#include "getflags.h"#include "exec.h"#include "io.h"#include "fns.h"/* * Search through the following code to see if we're just going to exit. */exitnext(void){ union code *c=&runq->code[runq->pc]; while(c->f==Xpopredir) c++; return c->f==Xexit;}void Xsimple(void){ word *a; thread *p=runq; var *v; struct builtin *bp; int pid, n; char buf[ERRMAX]; globlist(); a=runq->argv->words; if(a==0){ Xerror1("empty argument list"); return; } if(flag['x']) pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ v=gvlook(a->word); if(v->fn) execfunc(v); else{ if(strcmp(a->word, "builtin")==0){ if(count(a)==1){ pfmt(err, "builtin: empty argument list\n"); setstatus("empty arg list"); poplist(); return; } a=a->next; popword(); } for(bp=Builtin;bp->name;bp++) if(strcmp(a->word, bp->name)==0){ (*bp->fnc)(); return; } if(exitnext()){ /* fork and wait is redundant */ pushword("exec"); execexec(); Xexit(); } else{ flush(err); Updenv(); /* necessary so changes don't go out again */ switch(pid=fork()){ case -1: Xerror("try again"); return; case 0: pushword("exec"); execexec(); strcpy(buf, "can't exec: "); n = strlen(buf); errstr(buf+n, ERRMAX-n); Exit(buf); default: poplist(); /* interrupts don't get us out */ while(Waitfor(pid, 1) < 0) ; } } }}struct word nullpath={ "", 0};void doredir(redir *rp){ if(rp){ doredir(rp->next); switch(rp->type){ case ROPEN: if(rp->from!=rp->to){ Dup(rp->from, rp->to); close(rp->from); } break; case RDUP: Dup(rp->from, rp->to); break; case RCLOSE: close(rp->from); break; } }}word *searchpath(char *w){ word *path; if(strncmp(w, "/", 1)==0 || strncmp(w, "#", 1)==0 || strncmp(w, "./", 2)==0 || strncmp(w, "../", 3)==0 || (path=vlook("path")->val)==0) path=&nullpath; return path;}void execexec(void){ popword(); /* "exec" */ if(runq->argv->words==0){ Xerror1("empty argument list"); return; } doredir(runq->redir); Execute(runq->argv->words, searchpath(runq->argv->words->word)); poplist();}void execfunc(var *func){ word *starval; popword(); starval=runq->argv->words; runq->argv->words=0; poplist(); start(func->fn, func->pc, (struct var *)0); runq->local=newvar(strdup("*"), runq->local); runq->local->val=starval; runq->local->changed=1;}int dochdir(char *word){ /* report to /dev/wdir if it exists and we're interactive */ static int wdirfd = -2; if(chdir(word)<0) return -1; if(flag['i']!=0){ if(wdirfd==-2) /* try only once */ wdirfd = open("/dev/wdir", OWRITE|OCEXEC); if(wdirfd>=0) write(wdirfd, word, strlen(word)); } return 1;}void execcd(void){ word *a=runq->argv->words; word *cdpath; char dir[512]; setstatus("can't cd"); cdpath=vlook("cdpath")->val; switch(count(a)){ default: pfmt(err, "Usage: cd [directory]\n"); break; case 2: if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; for(;cdpath;cdpath=cdpath->next){ strcpy(dir, cdpath->word); if(dir[0]) strcat(dir, "/"); strcat(dir, a->next->word); if(dochdir(dir)>=0){ if(strlen(cdpath->word) && strcmp(cdpath->word, ".")!=0) pfmt(err, "%s\n", dir); setstatus(""); break; } } if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word); break; case 1: a=vlook("home")->val; if(count(a)>=1){ if(dochdir(a->word)>=0) setstatus(""); else pfmt(err, "Can't cd %s: %r\n", a->word); } else pfmt(err, "Can't cd -- $home empty\n"); break; } poplist();}void execexit(void){ switch(count(runq->argv->words)){ default: pfmt(err, "Usage: exit [status]\nExiting anyway\n"); case 2: setstatus(runq->argv->words->next->word); case 1: Xexit(); }}void execshift(void){ int n; word *a; var *star; switch(count(runq->argv->words)){ default: pfmt(err, "Usage: shift [n]\n"); setstatus("shift usage"); poplist(); return; case 2: n=atoi(runq->argv->words->next->word); break; case 1: n=1; break; } star=vlook("*"); for(;n && star->val;--n){ a=star->val->next; efree(star->val->word); efree((char *)star->val); star->val=a; star->changed=1; } setstatus(""); poplist();}int octal(char *s){ int n=0; while(*s==' ' || *s=='\t' || *s=='\n') s++; while('0'<=*s && *s<='7') n=n*8+*s++-'0'; return n;}int mapfd(int fd){ redir *rp; for(rp=runq->redir;rp;rp=rp->next){ switch(rp->type){ case RCLOSE: if(rp->from==fd) fd=-1; break; case RDUP: case ROPEN: if(rp->to==fd) fd=rp->from; break; } } return fd;}union code rdcmds[4];void execcmds(io *f){ static int first=1; if(first){ rdcmds[0].i=1; rdcmds[1].f=Xrdcmds; rdcmds[2].f=Xreturn; first=0; } start(rdcmds, 1, runq->local); runq->cmdfd=f; runq->iflast=0;}void execeval(void){ char *cmdline, *s, *t; int len=0; word *ap; if(count(runq->argv->words)<=1){ Xerror1("Usage: eval cmd ..."); return; } eflagok=1; for(ap=runq->argv->words->next;ap;ap=ap->next) len+=1+strlen(ap->word); cmdline=emalloc(len); s=cmdline; for(ap=runq->argv->words->next;ap;ap=ap->next){ for(t=ap->word;*t;) *s++=*t++; *s++=' '; } s[-1]='\n'; poplist(); execcmds(opencore(cmdline, len)); efree(cmdline);}union code dotcmds[14];void execdot(void){ int iflag=0; int fd; list *av; thread *p=runq; char *zero; static int first=1; char file[512]; word *path; if(first){ dotcmds[0].i=1; dotcmds[1].f=Xmark; dotcmds[2].f=Xword; dotcmds[3].s="0"; dotcmds[4].f=Xlocal; dotcmds[5].f=Xmark; dotcmds[6].f=Xword; dotcmds[7].s="*"; dotcmds[8].f=Xlocal; dotcmds[9].f=Xrdcmds; dotcmds[10].f=Xunlocal; dotcmds[11].f=Xunlocal; dotcmds[12].f=Xreturn; first=0; } else eflagok=1; popword(); if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ iflag=1; popword(); } /* get input file */ if(p->argv->words==0){ Xerror1("Usage: . [-i] file [arg ...]"); return; } zero=strdup(p->argv->words->word); popword(); fd=-1; for(path=searchpath(zero);path;path=path->next){ strcpy(file, path->word); if(file[0]) strcat(file, "/"); strcat(file, zero); if((fd=open(file, 0))>=0) break; if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ fd=Dup1(0); if(fd>=0) break; } } if(fd<0){ pfmt(err, "%s: ", zero); setstatus("can't open"); Xerror(".: can't open"); return; } /* set up for a new command loop */ start(dotcmds, 1, (struct var *)0); pushredir(RCLOSE, fd, 0); runq->cmdfile=zero; runq->cmdfd=openfd(fd); runq->iflag=iflag; runq->iflast=0; /* push $* value */ pushlist(); runq->argv->words=p->argv->words; /* free caller's copy of $* */ av=p->argv; p->argv=av->next; efree((char *)av); /* push $0 value */ pushlist(); pushword(zero); ndot++;}void execflag(void){ char *letter, *val; switch(count(runq->argv->words)){ case 2: setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set"); break; case 3: letter=runq->argv->words->next->word; val=runq->argv->words->next->next->word; if(strlen(letter)==1){ if(strcmp(val, "+")==0){ flag[letter[0]]=flagset; break; } if(strcmp(val, "-")==0){ flag[letter[0]]=0; break; } } default: Xerror1("Usage: flag [letter] [+-]"); return; } poplist();}void execwhatis(void){ /* mildly wrong -- should fork before writing */ word *a, *b, *path; var *v; struct builtin *bp; char file[512]; struct io out[1]; int found, sep; a=runq->argv->words->next; if(a==0){ Xerror1("Usage: whatis name ..."); return; } setstatus(""); out->fd=mapfd(1); out->bufp=out->buf; out->ebuf=&out->buf[NBUF]; out->strp=0; for(;a;a=a->next){ v=vlook(a->word); if(v->val){ pfmt(out, "%s=", a->word); if(v->val->next==0) pfmt(out, "%q\n", v->val->word); else{ sep='('; for(b=v->val;b && b->word;b=b->next){ pfmt(out, "%c%q", sep, b->word); sep=' '; } pfmt(out, ")\n"); } found=1; } else found=0; v=gvlook(a->word); if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); else{ for(bp=Builtin;bp->name;bp++) if(strcmp(a->word, bp->name)==0){ pfmt(out, "builtin %s\n", a->word); break; } if(!bp->name){ for(path=searchpath(a->word);path;path=path->next){ strcpy(file, path->word); if(file[0]) strcat(file, "/"); strcat(file, a->word); if(Executable(file)){ pfmt(out, "%s\n", file); break; } } if(!path && !found){ pfmt(err, "%s: not found\n", a->word); setstatus("not found"); } } } } poplist(); flush(err);}void execwait(void){ switch(count(runq->argv->words)){ default: Xerror1("Usage: wait [pid]"); return; case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break; case 1: Waitfor(-1, 0); break; } poplist();}
/*
* Maybe `simple' is a misnomer.
*/
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
/*
* Search through the following code to see if we're just going to exit.
*/
exitnext(void){
union code *c=&runq->code[runq->pc];
while(c->f==Xpopredir) c++;
return c->f==Xexit;
}
void Xsimple(void){
word *a;
thread *p=runq;
var *v;
struct builtin *bp;
int pid, n;
char buf[ERRMAX];
globlist();
a=runq->argv->words;
if(a==0){
Xerror1("empty argument list");
return;
}
if(flag['x'])
pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
v=gvlook(a->word);
if(v->fn)
execfunc(v);
else{
if(strcmp(a->word, "builtin")==0){
if(count(a)==1){
pfmt(err, "builtin: empty argument list\n");
setstatus("empty arg list");
poplist();
return;
}
a=a->next;
popword();
}
for(bp=Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
(*bp->fnc)();
return;
}
if(exitnext()){
/* fork and wait is redundant */
pushword("exec");
execexec();
Xexit();
}
else{
flush(err);
Updenv(); /* necessary so changes don't go out again */
switch(pid=fork()){
case -1:
Xerror("try again");
return;
case 0:
pushword("exec");
execexec();
strcpy(buf, "can't exec: ");
n = strlen(buf);
errstr(buf+n, ERRMAX-n);
Exit(buf);
default:
poplist();
/* interrupts don't get us out */
while(Waitfor(pid, 1) < 0)
;
}
}
}
}
struct word nullpath={ "", 0};
void doredir(redir *rp)
{
if(rp){
doredir(rp->next);
switch(rp->type){
case ROPEN:
if(rp->from!=rp->to){
Dup(rp->from, rp->to);
close(rp->from);
}
break;
case RDUP: Dup(rp->from, rp->to); break;
case RCLOSE: close(rp->from); break;
}
}
}
word *searchpath(char *w){
word *path;
if(strncmp(w, "/", 1)==0
|| strncmp(w, "#", 1)==0
|| strncmp(w, "./", 2)==0
|| strncmp(w, "../", 3)==0
|| (path=vlook("path")->val)==0)
path=&nullpath;
return path;
}
void execexec(void){
popword(); /* "exec" */
if(runq->argv->words==0){
Xerror1("empty argument list");
return;
}
doredir(runq->redir);
Execute(runq->argv->words, searchpath(runq->argv->words->word));
poplist();
}
void execfunc(var *func)
{
word *starval;
popword();
starval=runq->argv->words;
runq->argv->words=0;
poplist();
start(func->fn, func->pc, (struct var *)0);
runq->local=newvar(strdup("*"), runq->local);
runq->local->val=starval;
runq->local->changed=1;
}
int dochdir(char *word){
/* report to /dev/wdir if it exists and we're interactive */
static int wdirfd = -2;
if(chdir(word)<0) return -1;
if(flag['i']!=0){
if(wdirfd==-2) /* try only once */
wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
if(wdirfd>=0)
write(wdirfd, word, strlen(word));
}
return 1;
}
void execcd(void){
word *a=runq->argv->words;
word *cdpath;
char dir[512];
setstatus("can't cd");
cdpath=vlook("cdpath")->val;
switch(count(a)){
default:
pfmt(err, "Usage: cd [directory]\n");
break;
case 2:
if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
for(;cdpath;cdpath=cdpath->next){
strcpy(dir, cdpath->word);
if(dir[0]) strcat(dir, "/");
strcat(dir, a->next->word);
if(dochdir(dir)>=0){
if(strlen(cdpath->word)
&& strcmp(cdpath->word, ".")!=0)
pfmt(err, "%s\n", dir);
setstatus("");
break;
}
}
if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
break;
case 1:
a=vlook("home")->val;
if(count(a)>=1){
if(dochdir(a->word)>=0)
setstatus("");
else
pfmt(err, "Can't cd %s: %r\n", a->word);
}
else
pfmt(err, "Can't cd -- $home empty\n");
break;
}
poplist();
}
void execexit(void){
switch(count(runq->argv->words)){
default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
case 2: setstatus(runq->argv->words->next->word);
case 1: Xexit();
}
}
void execshift(void){
int n;
word *a;
var *star;
switch(count(runq->argv->words)){
default:
pfmt(err, "Usage: shift [n]\n");
setstatus("shift usage");
poplist();
return;
case 2: n=atoi(runq->argv->words->next->word); break;
case 1: n=1; break;
}
star=vlook("*");
for(;n && star->val;--n){
a=star->val->next;
efree(star->val->word);
efree((char *)star->val);
star->val=a;
star->changed=1;
}
setstatus("");
poplist();
}
int octal(char *s)
{
int n=0;
while(*s==' ' || *s=='\t' || *s=='\n') s++;
while('0'<=*s && *s<='7') n=n*8+*s++-'0';
return n;
}
int mapfd(int fd)
{
redir *rp;
for(rp=runq->redir;rp;rp=rp->next){
switch(rp->type){
case RCLOSE:
if(rp->from==fd) fd=-1;
break;
case RDUP:
case ROPEN:
if(rp->to==fd) fd=rp->from;
break;
}
}
return fd;
}
union code rdcmds[4];
void execcmds(io *f)
{
static int first=1;
if(first){
rdcmds[0].i=1;
rdcmds[1].f=Xrdcmds;
rdcmds[2].f=Xreturn;
first=0;
}
start(rdcmds, 1, runq->local);
runq->cmdfd=f;
runq->iflast=0;
}
void execeval(void){
char *cmdline, *s, *t;
int len=0;
word *ap;
if(count(runq->argv->words)<=1){
Xerror1("Usage: eval cmd ...");
return;
}
eflagok=1;
for(ap=runq->argv->words->next;ap;ap=ap->next)
len+=1+strlen(ap->word);
cmdline=emalloc(len);
s=cmdline;
for(ap=runq->argv->words->next;ap;ap=ap->next){
for(t=ap->word;*t;) *s++=*t++;
*s++=' ';
}
s[-1]='\n';
poplist();
execcmds(opencore(cmdline, len));
efree(cmdline);
}
union code dotcmds[14];
void execdot(void){
int iflag=0;
int fd;
list *av;
thread *p=runq;
char *zero;
static int first=1;
char file[512];
word *path;
if(first){
dotcmds[0].i=1;
dotcmds[1].f=Xmark;
dotcmds[2].f=Xword;
dotcmds[3].s="0";
dotcmds[4].f=Xlocal;
dotcmds[5].f=Xmark;
dotcmds[6].f=Xword;
dotcmds[7].s="*";
dotcmds[8].f=Xlocal;
dotcmds[9].f=Xrdcmds;
dotcmds[10].f=Xunlocal;
dotcmds[11].f=Xunlocal;
dotcmds[12].f=Xreturn;
first=0;
}
else
eflagok=1;
popword();
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
iflag=1;
popword();
}
/* get input file */
if(p->argv->words==0){
Xerror1("Usage: . [-i] file [arg ...]");
return;
}
zero=strdup(p->argv->words->word);
popword();
fd=-1;
for(path=searchpath(zero);path;path=path->next){
strcpy(file, path->word);
if(file[0]) strcat(file, "/");
strcat(file, zero);
if((fd=open(file, 0))>=0) break;
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
fd=Dup1(0);
if(fd>=0) break;
}
}
if(fd<0){
pfmt(err, "%s: ", zero);
setstatus("can't open");
Xerror(".: can't open");
return;
}
/* set up for a new command loop */
start(dotcmds, 1, (struct var *)0);
pushredir(RCLOSE, fd, 0);
runq->cmdfile=zero;
runq->cmdfd=openfd(fd);
runq->iflag=iflag;
runq->iflast=0;
/* push $* value */
pushlist();
runq->argv->words=p->argv->words;
/* free caller's copy of $* */
av=p->argv;
p->argv=av->next;
efree((char *)av);
/* push $0 value */
pushlist();
pushword(zero);
ndot++;
}
void execflag(void){
char *letter, *val;
switch(count(runq->argv->words)){
case 2:
setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
break;
case 3:
letter=runq->argv->words->next->word;
val=runq->argv->words->next->next->word;
if(strlen(letter)==1){
if(strcmp(val, "+")==0){
flag[letter[0]]=flagset;
break;
}
if(strcmp(val, "-")==0){
flag[letter[0]]=0;
break;
}
}
default:
Xerror1("Usage: flag [letter] [+-]");
return;
}
poplist();
}
void execwhatis(void){ /* mildly wrong -- should fork before writing */
word *a, *b, *path;
var *v;
struct builtin *bp;
char file[512];
struct io out[1];
int found, sep;
a=runq->argv->words->next;
if(a==0){
Xerror1("Usage: whatis name ...");
return;
}
setstatus("");
out->fd=mapfd(1);
out->bufp=out->buf;
out->ebuf=&out->buf[NBUF];
out->strp=0;
for(;a;a=a->next){
v=vlook(a->word);
if(v->val){
pfmt(out, "%s=", a->word);
if(v->val->next==0)
pfmt(out, "%q\n", v->val->word);
else{
sep='(';
for(b=v->val;b && b->word;b=b->next){
pfmt(out, "%c%q", sep, b->word);
sep=' ';
}
pfmt(out, ")\n");
}
found=1;
}
else
found=0;
v=gvlook(a->word);
if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
else{
for(bp=Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
pfmt(out, "builtin %s\n", a->word);
break;
}
if(!bp->name){
for(path=searchpath(a->word);path;path=path->next){
strcpy(file, path->word);
if(file[0]) strcat(file, "/");
strcat(file, a->word);
if(Executable(file)){
pfmt(out, "%s\n", file);
break;
}
}
if(!path && !found){
pfmt(err, "%s: not found\n", a->word);
setstatus("not found");
}
}
}
}
poplist();
flush(err);
}
void execwait(void){
switch(count(runq->argv->words)){
default: Xerror1("Usage: wait [pid]"); return;
case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
case 1: Waitfor(-1, 0); break;
}
poplist();
}