123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- /*
- * 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.
- */
- int
- 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;
- 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 */
- if((pid = execforkexec()) < 0){
- Xerror("try again");
- return;
- }
- /* interrupts don't get us out */
- poplist();
- 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, runq->local);
- 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;
- 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){
- if(cdpath->word[0] != '\0')
- dir = smprint("%s/%s", cdpath->word,
- a->next->word);
- else
- dir = strdup(a->next->word);
- if(dochdir(dir) >= 0){
- if(cdpath->word[0] != '\0' &&
- strcmp(cdpath->word, ".") != 0)
- pfmt(err, "%s\n", dir);
- free(dir);
- setstatus("");
- break;
- }
- free(dir);
- }
- 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, *file;
- word *path;
- static int first = 1;
- 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){
- if(path->word[0] != '\0')
- file = smprint("%s/%s", path->word, zero);
- else
- file = strdup(zero);
- fd = open(file, 0);
- free(file);
- if(fd >= 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[(uchar)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[(uchar)letter[0]] = flagset;
- break;
- }
- if(strcmp(val, "-")==0){
- flag[(uchar)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;
- 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 %q %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){
- if(path->word[0] != '\0')
- file = smprint("%s/%s",
- path->word, a->word);
- else
- file = strdup(a->word);
- if(Executable(file)){
- pfmt(out, "%s\n", file);
- free(file);
- break;
- }
- free(file);
- }
- 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();
- }
|