From d1a19f0d477a6249d8af9322317b8434b86260ea Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Wed, 13 Oct 2021 08:27:37 -0700 Subject: fix(email): bytes error. updated vendoring --- sys/cmd/rc/exec.c | 1077 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 976 insertions(+), 101 deletions(-) (limited to 'sys/cmd/rc/exec.c') diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c index 0155b22..15d1cdf 100644 --- a/sys/cmd/rc/exec.c +++ b/sys/cmd/rc/exec.c @@ -1,139 +1,1014 @@ #include "rc.h" +#include "getflags.h" +#include "exec.h" +#include "io.h" +#include "fns.h" +/* + * Start executing the given code at the given pc with the given redirection + */ +char *argv0="rc"; +int ndot; +int lastc; +int kidpid; +int mypid; -#define W0 shell->stack->words -// ----------------------------------------------------------------------- -// helper functions +thread *runq; +code *codebuf; /* compiler output */ +int ntrap; /* number of outstanding traps */ +int trap[NSIG]; /* number of outstanding traps per type */ + +int eflagok; /* kludge flag so that -e doesn't exit in startup */ + +char **argp; +char **args; +int nerror; /* number of errors encountered during compilation */ -static void -setstatus(char *s) +start(code *c, int pc, var *local) +{ + struct thread *p = new(struct thread); + + p->code = codecopy(c); + p->pc = pc; + p->argv = 0; + p->redir = p->startredir = runq?runq->redir:0; + p->local = local; + p->cmdfile = 0; + p->cmdfd = 0; + p->eof = 0; + p->iflag = 0; + p->lineno = 1; + p->ret = runq; + runq = p; +} + +word* +newword(char *wd, word *next) { - setvar("status", newword(s, nil)); + word *p = new(word); + p->word = strdup(wd); + p->next = next; + return p; } -static void -pushredir(int type, int from, int to) +pushword(char *wd) { - Redir *r; + if(runq->argv==0) + panic("pushword but no argv!", 0); + runq->argv->words = newword(wd, runq->argv->words); +} - alloc(r); - r->type = type; - r->from = from; - r->to = to; - r->link = shell->redir, shell->redir = r; +void +popword(void) +{ + word *p; + if(runq->argv==0) + panic("popword but no argv!", 0); + p = runq->argv->words; + if(p==0) + panic("popword but no word!", 0); + runq->argv->words = p->next; + efree(p->word); + efree((char *)p); } -// ----------------------------------------------------------------------- -// interpreter functions +void +freelist(word *w) +{ + word *nw; + while(w){ + nw = w->next; + efree(w->word); + efree((char *)w); + w = nw; + } +} void -Xerror(char *s) +pushlist(void) +{ + list *p = new(list); + p->next = runq->argv; + p->words = 0; + runq->argv = p; +} + +void +poplist(void) +{ + list *p = runq->argv; + if(p==0) + panic("poplist but no argv", 0); + freelist(p->words); + runq->argv = p->next; + efree((char *)p); +} + +int +count(word *w) +{ + int n; + for(n = 0;w;n++) w = w->next; + return n; +} + +void +pushredir(int type, int from, int to) { - if(!strcmp(argv0, "rc")||!strcmp(argv0, "/bin/rc")) - pfmt(errio, "rc: %s: %r\n", s); - else - pfmt(errio, "rc (%s): %s: %r\n", argv0, s); - flush(&errio); + redir * rp = new(redir); + rp->type = type; + rp->from = from; + rp->to = to; + rp->next = runq->redir; + runq->redir = rp; +} - setstatus("error"); - while(!shell->interactive) - Xkill(); +var* +newvar(char *name, var *next) +{ + var *v = new(var); + v->name = name; + v->val = 0; + v->fn = 0; + v->changed = 0; + v->fnchanged = 0; + v->next = next; + v->changefn = 0; + return v; } +/* + * get command line flags, initialize keywords & traps. + * get values from environment. + * set $pid, $cflag, $* + * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*) + * start interpreting code + */ +int +main(int argc, char *argv[]) +{ + code bootstrap[32]; + char num[12], *rcmain; + int i; + + argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1); + if(argc==-1) + usage("[file [arg ...]]"); + if(argv[0][0]=='-') + flag['l'] = flagset; + if(flag['I']) + flag['i'] = 0; + else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset; + rcmain = flag['m'] ? flag['m'][0] : Rcmain; + err = openfd(2); + kinit(); + Trapinit(); + Vinit(); + inttoascii(num, mypid = getpid()); + pathinit(); + setvar("pid", newword(num, (word *)0)); + setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0) + :(word *)0); + setvar("rcname", newword(argv[0], (word *)0)); + i = 0; + memset(bootstrap, 0, sizeof bootstrap); + bootstrap[i++].i = 1; + bootstrap[i++].f = Xmark; + bootstrap[i++].f = Xword; + bootstrap[i++].s="*"; + bootstrap[i++].f = Xassign; + bootstrap[i++].f = Xmark; + bootstrap[i++].f = Xmark; + bootstrap[i++].f = Xword; + bootstrap[i++].s="*"; + bootstrap[i++].f = Xdol; + bootstrap[i++].f = Xword; + bootstrap[i++].s = rcmain; + bootstrap[i++].f = Xword; + bootstrap[i++].s="."; + bootstrap[i++].f = Xsimple; + bootstrap[i++].f = Xexit; + bootstrap[i].i = 0; + start(bootstrap, 1, (var *)0); + /* prime bootstrap argv */ + pushlist(); + argv0 = strdup(argv[0]); + for(i = argc-1;i!=0;--i) pushword(argv[i]); + for(;;){ + if(flag['r']) + pfnc(err, runq); + runq->pc++; + (*runq->code[runq->pc-1].f)(); + if(ntrap) + dotrap(); + } + return 0; /* not reached; silence OS X Lion gcc */ +} +/* + * Opcode routines + * Arguments on stack (...) + * Arguments in line [...] + * Code in line with jump around {...} + * + * Xappend(file)[fd] open file to append + * Xassign(name, val) assign val to name + * Xasync{... Xexit} make thread for {}, no wait + * Xbackq{... Xreturn} make thread for {}, push stdout + * Xbang complement condition + * Xcase(pat, value){...} exec code on match, leave (value) on + * stack + * Xclose[i] close file descriptor + * Xconc(left, right) concatenate, push results + * Xcount(name) push var count + * Xdelfn(name) delete function definition + * Xdeltraps(names) delete named traps + * Xdol(name) get variable value + * Xqdol(name) concatenate variable components + * Xdup[i j] dup file descriptor + * Xexit rc exits with status + * Xfalse{...} execute {} if false + * Xfn(name){... Xreturn} define function + * Xfor(var, list){... Xreturn} for loop + * Xjump[addr] goto + * Xlocal(name, val) create local variable, assign value + * Xmark mark stack + * Xmatch(pat, str) match pattern, set status + * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads, + * wait for both + * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output, + * depending on type), push /dev/fd/?? + * Xpopm(value) pop value from stack + * Xrdwr(file)[fd] open file for reading and writing + * Xread(file)[fd] open file to read + * Xsettraps(names){... Xreturn} define trap functions + * Xshowtraps print trap list + * Xsimple(args) run command and wait + * Xreturn kill thread + * Xsubshell{... Xexit} execute {} in a subshell and wait + * Xtrue{...} execute {} if true + * Xunlocal delete local variable + * Xword[string] push string + * Xwrite(file)[fd] open file to write + */ void Xappend(void) { - int fd; - char *path; + char *file; + int f; + switch(count(runq->argv->words)){ + default: + Xerror1(">> requires singleton"); + return; + case 0: + Xerror1(">> requires file"); + return; + case 1: + break; + } + file = runq->argv->words->word; + if((f = open(file, 1))<0 && (f = Creat(file))<0){ + pfmt(err, "%s: ", file); + Xerror("can't open"); + return; + } + Seek(f, 0L, 2); + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} - switch(count(W0)) { - default: - Xerror(">> requires a singleton list"); - return; - case 0: - Xerror(">> requires one file"); - return; - case 1: - ; - } +void +Xsettrue(void) +{ + setstatus(""); +} - path = shell->stack->words->word; - if ((fd=open(path, 1))< 0 && (fd=creat(path, 0666L))<0) { - pfmt(errio, "%s: ", path); - Xerror("can't open"); - return; - } - lseek(fd, 0L, 2); - pushredir(Fopen, fd, shell->ip++->i); - poplist(); +void +Xbang(void) +{ + setstatus(truestatus()?"false":""); } void -Xassign(void) +Xclose(void) +{ + pushredir(RCLOSE, runq->code[runq->pc].i, 0); + runq->pc++; +} + +void +Xdup(void) +{ + pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); + runq->pc+=2; +} + +void +Xeflag(void) +{ + if(eflagok && !truestatus()) Xexit(); +} + +void +Xexit(void) +{ + struct var *trapreq; + struct word *starval; + static int beenhere = 0; + if(getpid()==mypid && !beenhere){ + trapreq = vlook("sigexit"); + if(trapreq->fn){ + beenhere = 1; + --runq->pc; + starval = vlook("*")->val; + start(trapreq->fn, trapreq->pc, (struct var *)0); + runq->local = newvar(strdup("*"), runq->local); + runq->local->val = copywords(starval, (struct word *)0); + runq->local->changed = 1; + runq->redir = runq->startredir = 0; + return; + } + } + Exit(getstatus()); +} + +void +Xfalse(void) { - Var *v; - if(count(W0)!=1) { - Xerror("variable name not singleton"); - return; - } - unglob(W0->word); - v = vlookup(W0->word); - poplist(); - globlist(); - freelist(v->val); + if(truestatus()) runq->pc = runq->code[runq->pc].i; + else runq->pc++; +} +int ifnot; /* dynamic if not flag */ - v->val = W0; - if(v->update) - v->update(v); - W0 = nil; - poplist(); +void +Xifnot(void) +{ + if(ifnot) + runq->pc++; + else + runq->pc = runq->code[runq->pc].i; +} + +void +Xjump(void) +{ + runq->pc = runq->code[runq->pc].i; } void Xmark(void) { - pushlist(); + pushlist(); +} + +void +Xpopm(void) +{ + poplist(); +} + +void +Xread(void) +{ + char *file; + int f; + switch(count(runq->argv->words)){ + default: + Xerror1("< requires singleton\n"); + return; + case 0: + Xerror1("< requires file\n"); + return; + case 1: + break; + } + file = runq->argv->words->word; + if((f = open(file, 0))<0){ + pfmt(err, "%s: ", file); + Xerror("can't open"); + return; + } + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +void +Xrdwr(void) +{ + char *file; + int f; + + switch(count(runq->argv->words)){ + default: + Xerror1("<> requires singleton\n"); + return; + case 0: + Xerror1("<> requires file\n"); + return; + case 1: + break; + } + file = runq->argv->words->word; + if((f = open(file, ORDWR))<0){ + pfmt(err, "%s: ", file); + Xerror("can't open"); + return; + } + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +void +turfredir(void) +{ + while(runq->redir!=runq->startredir) + Xpopredir(); +} + +void +Xpopredir(void) +{ + struct redir *rp = runq->redir; + if(rp==0) + panic("turfredir null!", 0); + runq->redir = rp->next; + if(rp->type==ROPEN) + close(rp->from); + efree((char *)rp); +} + +void +Xreturn(void) +{ + struct thread *p = runq; + turfredir(); + while(p->argv) poplist(); + codefree(p->code); + runq = p->ret; + efree((char *)p); + if(runq==0) + Exit(getstatus()); +} + +void +Xtrue(void) +{ + if(truestatus()) runq->pc++; + else runq->pc = runq->code[runq->pc].i; +} + +void +Xif(void) +{ + ifnot = 1; + if(truestatus()) runq->pc++; + else runq->pc = runq->code[runq->pc].i; +} + +void +Xwastrue(void) +{ + ifnot = 0; } void Xword(void) { - pushword(shell->ip++->s); -} - -void Xasync(void); -void Xcat(void); -void Xclose(void); -void Xcmdsub(void); -void Xcount(void); -void Xdol(void); -void Xdup(void); -void Xexit(void); -void Xfalse(void); -void Xflatten(void); -void Xfor(void); -void Xfunc(void); -void Xglob(void); -void Xif(void); -void Xjump(void); -void Xkill(void); -void Xlocal(void); -void Xmark(void); -void Xmatch(void); -void Xnegate(void); -void Xpipe(void); -void Xpipefd(void); -void Xpipewait(void); -void Xpop(void); -void Xpopredir(void); -void Xrdwr(void); -void Xread(void); -void Xsub(void); -void Xsimple(void); -void Xsubshell(void); -void Xtrue(void); -void Xunfunc(void); -void Xunlocal(void); -void Xword(void); -void Xwrite(void); + pushword(runq->code[runq->pc++].s); +} + +void +Xwrite(void) +{ + char *file; + int f; + switch(count(runq->argv->words)){ + default: + Xerror1("> requires singleton\n"); + return; + case 0: + Xerror1("> requires file\n"); + return; + case 1: + break; + } + file = runq->argv->words->word; + if((f = Creat(file))<0){ + pfmt(err, "%s: ", file); + Xerror("can't open"); + return; + } + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +char* +list2str(word *words) +{ + char *value, *s, *t; + int len = 0; + word *ap; + for(ap = words;ap;ap = ap->next) + len+=1+strlen(ap->word); + value = emalloc(len+1); + s = value; + for(ap = words;ap;ap = ap->next){ + for(t = ap->word;*t;) *s++=*t++; + *s++=' '; + } + if(s==value) + *s='\0'; + else s[-1]='\0'; + return value; +} + +void +Xmatch(void) +{ + word *p; + char *subject; + subject = list2str(runq->argv->words); + setstatus("no match"); + for(p = runq->argv->next->words;p;p = p->next) + if(match(subject, p->word, '\0')){ + setstatus(""); + break; + } + efree(subject); + poplist(); + poplist(); +} + +void +Xcase(void) +{ + word *p; + char *s; + int ok = 0; + s = list2str(runq->argv->next->words); + for(p = runq->argv->words;p;p = p->next){ + if(match(s, p->word, '\0')){ + ok = 1; + break; + } + } + efree(s); + if(ok) + runq->pc++; + else + runq->pc = runq->code[runq->pc].i; + poplist(); +} + +word* +conclist(word *lp, word *rp, word *tail) +{ + char *buf; + word *v; + if(lp->next || rp->next) + tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next, + tail); + buf = emalloc(strlen(lp->word)+strlen(rp->word)+1); + strcpy(buf, lp->word); + strcat(buf, rp->word); + v = newword(buf, tail); + efree(buf); + return v; +} + +void +Xconc(void) +{ + word *lp = runq->argv->words; + word *rp = runq->argv->next->words; + word *vp = runq->argv->next->next->words; + int lc = count(lp), rc = count(rp); + if(lc!=0 || rc!=0){ + if(lc==0 || rc==0){ + Xerror1("null list in concatenation"); + return; + } + if(lc!=1 && rc!=1 && lc!=rc){ + Xerror1("mismatched list lengths in concatenation"); + return; + } + vp = conclist(lp, rp, vp); + } + poplist(); + poplist(); + runq->argv->words = vp; +} + +void +Xassign(void) +{ + var *v; + if(count(runq->argv->words)!=1){ + Xerror1("variable name not singleton!"); + return; + } + deglob(runq->argv->words->word); + v = vlook(runq->argv->words->word); + poplist(); + globlist(); + freewords(v->val); + v->val = runq->argv->words; + v->changed = 1; + if(v->changefn) + v->changefn(v); + runq->argv->words = 0; + poplist(); +} +/* + * copy arglist a, adding the copy to the front of tail + */ + +word* +copywords(word *a, word *tail) +{ + word *v = 0, **end; + for(end=&v;a;a = a->next,end=&(*end)->next) + *end = newword(a->word, 0); + *end = tail; + return v; +} + +void +Xdol(void) +{ + word *a, *star; + char *s, *t; + int n; + if(count(runq->argv->words)!=1){ + Xerror1("variable name not singleton!"); + return; + } + s = runq->argv->words->word; + deglob(s); + n = 0; + for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; + a = runq->argv->next->words; + if(n==0 || *t) + a = copywords(vlook(s)->val, a); + else{ + star = vlook("*")->val; + if(star && 1<=n && n<=count(star)){ + while(--n) star = star->next; + a = newword(star->word, a); + } + } + poplist(); + runq->argv->words = a; +} + +void +Xqdol(void) +{ + word *a, *p; + char *s; + int n; + if(count(runq->argv->words)!=1){ + Xerror1("variable name not singleton!"); + return; + } + s = runq->argv->words->word; + deglob(s); + a = vlook(s)->val; + poplist(); + n = count(a); + if(n==0){ + pushword(""); + return; + } + for(p = a;p;p = p->next) n+=strlen(p->word); + s = emalloc(n); + if(a){ + strcpy(s, a->word); + for(p = a->next;p;p = p->next){ + strcat(s, " "); + strcat(s, p->word); + } + } + else + s[0]='\0'; + pushword(s); + efree(s); +} + +word* +copynwords(word *a, word *tail, int n) +{ + word *v, **end; + + v = 0; + end = &v; + while(n-- > 0){ + *end = newword(a->word, 0); + end = &(*end)->next; + a = a->next; + } + *end = tail; + return v; +} + +word* +subwords(word *val, int len, word *sub, word *a) +{ + int n, m; + char *s; + if(!sub) + return a; + a = subwords(val, len, sub->next, a); + s = sub->word; + deglob(s); + m = 0; + n = 0; + while('0'<=*s && *s<='9') + n = n*10+ *s++ -'0'; + if(*s == '-'){ + if(*++s == 0) + m = len - n; + else{ + while('0'<=*s && *s<='9') + m = m*10+ *s++ -'0'; + m -= n; + } + } + if(n<1 || n>len || m<0) + return a; + if(n+m>len) + m = len-n; + while(--n > 0) + val = val->next; + return copynwords(val, a, m+1); +} + +void +Xsub(void) +{ + word *a, *v; + char *s; + if(count(runq->argv->next->words)!=1){ + Xerror1("variable name not singleton!"); + return; + } + s = runq->argv->next->words->word; + deglob(s); + a = runq->argv->next->next->words; + v = vlook(s)->val; + a = subwords(v, count(v), runq->argv->words, a); + poplist(); + poplist(); + runq->argv->words = a; +} + +void +Xcount(void) +{ + word *a; + char *s, *t; + int n; + char num[12]; + if(count(runq->argv->words)!=1){ + Xerror1("variable name not singleton!"); + return; + } + s = runq->argv->words->word; + deglob(s); + n = 0; + for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; + if(n==0 || *t){ + a = vlook(s)->val; + inttoascii(num, count(a)); + } + else{ + a = vlook("*")->val; + inttoascii(num, a && 1<=n && n<=count(a)?1:0); + } + poplist(); + pushword(num); +} + +void +Xlocal(void) +{ + if(count(runq->argv->words)!=1){ + Xerror1("variable name must be singleton\n"); + return; + } + deglob(runq->argv->words->word); + runq->local = newvar(strdup(runq->argv->words->word), runq->local); + runq->local->val = copywords(runq->argv->next->words, (word *)0); + runq->local->changed = 1; + poplist(); + poplist(); +} + +void +Xunlocal(void) +{ + var *v = runq->local, *hid; + if(v==0) + panic("Xunlocal: no locals!", 0); + runq->local = v->next; + hid = vlook(v->name); + hid->changed = 1; + efree(v->name); + freewords(v->val); + efree((char *)v); +} + +void +freewords(word *w) +{ + word *nw; + while(w){ + efree(w->word); + nw = w->next; + efree((char *)w); + w = nw; + } +} + +void +Xfn(void) +{ + var *v; + word *a; + int end; + end = runq->code[runq->pc].i; + for(a = runq->argv->words;a;a = a->next){ + v = gvlook(a->word); + if(v->fn) + codefree(v->fn); + v->fn = codecopy(runq->code); + v->pc = runq->pc+2; + v->fnchanged = 1; + } + runq->pc = end; + poplist(); +} + +void +Xdelfn(void) +{ + var *v; + word *a; + for(a = runq->argv->words;a;a = a->next){ + v = gvlook(a->word); + if(v->fn) + codefree(v->fn); + v->fn = 0; + v->fnchanged = 1; + } + poplist(); +} + +char* +concstatus(char *s, char *t) +{ + static char v[NSTATUS+1]; + int n = strlen(s); + strncpy(v, s, NSTATUS); + if(npid==-1) + setstatus(concstatus(runq->status, getstatus())); + else{ + strncpy(status, getstatus(), NSTATUS); + status[NSTATUS]='\0'; + Waitfor(runq->pid, 1); + runq->pid=-1; + setstatus(concstatus(getstatus(), status)); + } +} + +void +Xrdcmds(void) +{ + struct thread *p = runq; + word *prompt; + flush(err); + nerror = 0; + if(flag['s'] && !truestatus()) + pfmt(err, "status=%v\n", vlook("status")->val); + if(runq->iflag){ + prompt = vlook("prompt")->val; + if(prompt) + promptstr = prompt->word; + else + promptstr="% "; + } + Noerror(); + if(yyparse()){ + if(!p->iflag || p->eof && !Eintr()){ + if(p->cmdfile) + efree(p->cmdfile); + closeio(p->cmdfd); + Xreturn(); /* should this be omitted? */ + } + else{ + if(Eintr()){ + pchr(err, '\n'); + p->eof = 0; + } + --p->pc; /* go back for next command */ + } + } + else{ + ntrap = 0; /* avoid double-interrupts during blocked writes */ + --p->pc; /* re-execute Xrdcmds after codebuf runs */ + start(codebuf, 1, runq->local); + } + freenodes(); +} + +void +Xerror(char *s) +{ + if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) + pfmt(err, "rc: %s: %r\n", s); + else + pfmt(err, "rc (%s): %s: %r\n", argv0, s); + flush(err); + setstatus("error"); + while(!runq->iflag) Xreturn(); +} + +void +Xerror1(char *s) +{ + if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) + pfmt(err, "rc: %s\n", s); + else + pfmt(err, "rc (%s): %s\n", argv0, s); + flush(err); + setstatus("error"); + while(!runq->iflag) Xreturn(); +} + +void +setstatus(char *s) +{ + setvar("status", newword(s, (word *)0)); +} + +char* +getstatus(void) +{ + var *status = vlook("status"); + return status->val?status->val->word:""; +} + +int +truestatus(void) +{ + char *s; + for(s = getstatus();*s;s++) + if(*s!='|' && *s!='0') + return 0; + return 1; +} + +void +Xdelhere(void) +{ + Unlink(runq->code[runq->pc++].s); +} + +void +Xfor(void) +{ + if(runq->argv->words==0){ + poplist(); + runq->pc = runq->code[runq->pc].i; + } + else{ + freelist(runq->local->val); + runq->local->val = runq->argv->words; + runq->local->changed = 1; + runq->argv->words = runq->argv->words->next; + runq->local->val->next = 0; + runq->pc++; + } +} + +void +Xglob(void) +{ + globlist(); +} -- cgit v1.2.1