ref: 887ae1a17b54babf6a0946872bf6faaac1427be1
dir: /sys/src/cmd/rc/simple.c/
/* * 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("*", 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 = estrdup(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 = estrdup(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 = estrdup(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 = estrdup(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(); }