From ce05175372a9ddca1a225db0765ace1127a39293 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 12 Nov 2021 09:22:01 -0800 Subject: chore: simplified organizational structure --- sys/cmd/rc/exec.c | 1267 ----------------------------------------------------- 1 file changed, 1267 deletions(-) delete mode 100644 sys/cmd/rc/exec.c (limited to 'sys/cmd/rc/exec.c') diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c deleted file mode 100644 index 5baaf1a..0000000 --- a/sys/cmd/rc/exec.c +++ /dev/null @@ -1,1267 +0,0 @@ -#include "rc.h" -#include "exec.h" - -#include - -int yyparse(void); - -struct Builtin{ - char *name; - void (*func)(void); -}; - -struct State { - int async; -}; - -static struct State state; - -// ----------------------------------------------------------------------- -// globals - -static Word nullpath = { .str="", .link=nil }; - -struct Builtin builtin[]={ - {"cd", xcd}, - {".", xdot}, - {"echo", xecho}, - {"exit", xexit}, - {"fg", xfg}, - {"jobs", xjob}, - 0, -}; - -// ----------------------------------------------------------------------- -// internal - -/* words and lists */ - -static -void -pushword(char *str) -{ - if(!runner->args) - fatal("attempt to push on empty argument stack\n"); - - runner->args->word = makeword(str, runner->args->word); -} - -static -void -popword(void) -{ - Word *w; - if(!runner->args) - fatal("tried to pop word on empty argument stack\n"); - - w = runner->args->word; - if(!w) - fatal("tried to pop word but nothing there\n"); - - runner->args->word = w->link; - efree(w->str); - efree(w); -} - -static -Word* -copywords(Word *a, Word *tail) -{ - Word *v = nil, **end; - - for(end=&v; a; a = a->link,end=&(*end)->link) - *end = makeword(a->str, nil); - *end = tail; - - return v; -} - -static -void -freewords(Word *w) -{ - Word *n; - while(w){ - efree(w->str); - n = w->link; - efree(w); - w = n; - } -} - -static -void -freelist(Word *w) -{ - Word *n; - while(w){ - n = w->link; - efree(w->str); - efree(w); - w = n; - } - -} - -static -void -pushlist(void) -{ - List *stack = emalloc(sizeof(*stack)); - - stack->word = nil; - stack->link = runner->args; - - runner->args = stack; -} - -static -void -poplist(void) -{ - List *stack = runner->args; - if(!stack) - fatal("attempted to pop an empty argument stack\n"); - - freelist(stack->word); - runner->args = stack->link; - efree(stack); -} - -/* system interop */ -static -Word* -path(char *w) -{ - Word *path; - - if(strncmp(w, "/", 1)==0 - || strncmp(w, "./", 2)==0 - || strncmp(w, "../", 3)==0 - || (path = var("path")->val)==0) - path=&nullpath; - - return path; -} - -static inline -void -undoredirs(void) -{ - while(runner->redir.end != runner->redir.start) - Xpopredir(); -} - -static inline -int -exitsnext(void) -{ - Code *c = &runner->code.exe[runner->code.i]; - while(c->f == Xpopredir) - c++; - - return c->f == Xexit; -} - -static inline -void -defaultsignal(void) -{ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - signal(SIGCHLD, SIG_DFL); -} - -static inline -void -setpid(Thread *job, int pid) -{ - job->pid = pid; - if(job->pgid <= 0){ - job->pgid = pid; - addjob(job); - } - - setpgid(pid, job->pgid); -} - -/* fork/execute helpers */ - -static inline -void -initchild(Thread *job, int fg) -{ - int pid = getpid(); - setpid(job, pid); - - if(job->flag.user){ - if(fg) - tcsetpgrp(0, job->pgid); - else - job->flag.user = 0; - defaultsignal(); - } - - clearwait(job); -} - -static inline -void -initparent(Thread *job, int pid, int fg) -{ - setpid(job, pid); - - if(job->flag.user){ - if(!fg){ - tcsetpgrp(0, job->pgid); - job->flag.user = 0; - } - } - addwait(job, pid); -} - -static -void -xx(void) -{ - popword(); // "exec" - if(!runner->args->word){ - Xerror("empty argument list"); - return; - } - - redirect(runner->redir.end); - execute(runner->args->word, path(runner->args->word->str)); - poplist(); -} - -static -int -xforkx(void) -{ - int n, pid; - - switch(pid=fork()){ - case -1: - Xerror("try again\n"); - return -1; - case 0: // child - initchild(runner, 1); - - pushword("exec"); - xx(); - - exit(2); // NOTE: unreachable: xx does not return - default: // parent - initparent(runner, pid, 0); - - return pid; - } -} - -/* redirections */ -void -pushredir(int type, int from, int to) -{ - Redir *r = emalloc(sizeof(*r)); - - r->type = type; - r->from = from; - r->to = to; - - r->link = runner->redir.end, runner->redir.end = r; -} - -/* byte code */ -static -void -run(Code *c, int pc, Var *local, int inherit) -{ - Thread *new = emalloc(sizeof(*new)); - - new->code.i = pc; - new->code.exe = copycode(c); - - new->cmd.path = nil; - new->cmd.io = nil; - - new->args = nil; - new->local = local; - - new->flag.eof = 0; - if(runner){ - new->pid = runner->pid; - new->flag.user = runner->flag.user; - new->redir.end = new->redir.start = runner->redir.end; - }else{ - new->pid = shell.pid; - new->flag.user = shell.interactive; - new->redir.end = new->redir.start = nil; - } - - new->wait.status = 0; - new->wait.len = 0; - new->wait.cap = 0; - new->wait.on = nil; - - new->status = 0; - if(inherit) - new->pgid = runner->pgid; - else - new->pgid = -1; - - new->line = 0; - new->caller = runner; - new->link = nil; - - runner = new; -} - -// ----------------------------------------------------------------------- -// exported builtins - -// XXX: find a better place for these -Word* -makeword(char *str, Word *link) -{ - Word *w = emalloc(sizeof(*w)); - - w->str = strdup(str); - w->link = link; - - return w; -} - -void -freeword(Word *word) -{ - Word *n; - - while(word){ - efree(word->str); - n = word->link; - efree(word); - word = n; - } -} - -int -count(Word *w) -{ - int n; - for(n = 0; w; n++) - w = w->link; - return n; -} - -// ----------------------------------------------------------------------- -// builtins - -void -xecho(void) -{ - int fd; - Word *arg; - char *b, *s, buf[128]; - - fd = mapfd(1); - b = buf; - - popword(); // echo - - // TODO: controllable flags here - arg = runner->args->word; -printword: - s = arg->str; - while(*s){ - *b++ = *s++; - if(b == arrend(buf)-2) // always have 2 bytes available - write(fd, buf, arrlen(buf)-2), b = buf; - } - - arg = arg->link; - if(arg){ - *b++ = ' '; - goto printword; - }else{ - *b++ = '\n'; - *b++ = 0; - /* fallthrough */ - } - write(fd, buf, b-buf); - - poplist(); -} - -void -xexit(void) -{ - Word *arg; - - popword(); // exit - arg = runner->args->word; - switch(count(arg)){ - default: - print(shell.err, "invalid number of arguments to exit, exiting anyways\n"); - case 0: - Xexit(); - } - /* unreachable */ -} - -void -xcd(void) -{ - Word *arg; - Word *cdpath; - char dir[512]; - - popword(); // cd - - arg = runner->args->word; - switch(count(arg)){ - default: - print(shell.err, "usage: cd [directory]\n"); - break; - case 0: - arg = var("home")->val; - if(count(arg) >= 1){ - if(chdir(arg->str) < 0) - print(shell.err, "failed cd: %s\n", strerror(errno)); - }else{ - print(shell.err, "ambiguous cd: $home empty\n"); - } - break; - - case 1: - // TODO: add cdpath - cdpath = &nullpath; - for(; cdpath; cdpath = cdpath->link){ - strcpy(dir, cdpath->str); - if(dir[0]) - strcat(dir,"/"); - strcat(dir, arg->str); - if(chdir(dir) < 0){ - print(shell.err, "failed cd %s: %s\n", dir, strerror(errno)); - } - break; - } - break; - } - - poplist(); -} - -static Code dotcmd[14] = -{ - [0] = {.i = 0}, - [1] = {.f = Xmark}, - [2] = {.f = Xword}, - [3] = {.s = "0"}, - [4] = {.f = Xlocal}, - [5] = {.f = Xmark}, - [6] = {.f = Xword}, - [7] = {.s = "*"}, - [8] = {.f = Xlocal}, - [9] = {.f = Xreadcmd}, - [10] = {.f = Xunlocal}, - [11] = {.f = Xunlocal}, - [12] = {.f = Xreturn}, -}; - -void -xdot(void) -{ - Word *p; - List *argv; - char *base; - int fd, iflag = 0; - Thread *old; - char file[512]; - - popword(); // "." -#if 0 - if(proc->args->word && strcmp(proc->args->word->str, "-i")==0){ - iflag = 1; - popword(); - } -#endif - /* get input file */ - if(!runner->args->word){ - Xerror("usage: . [-i] file [arg ...]\n"); - return; - } - - base = strdup(runner->args->word->str); - popword(); - for(fd=-1, p=path(base); p; p = p->link){ - strcpy(file, p->str); - - if(file[0]) - strcat(file, "/"); - strcat(file, base); - - if((fd = open(file, 0))>=0) - break; - } - - if(fd<0){ - print(shell.err, "failed open: %s: ", base); - return; - } - /* set up for a new command loop */ - old = runner; // store pointer to old code - run(dotcmd, 1, nil, 0); - - /* operations on new command stack */ - pushredir(Rclose, fd, 0); - runner->cmd.path = base; - runner->cmd.io = openfd(fd); - - /* push $* value */ - pushlist(); - runner->args->word = old->args->word; - - /* free caller's copy of $* */ - argv = old->args; - old->args = argv->link; - efree(argv); - - /* push $0 value */ - pushlist(); - pushword(base); - //ndot++; -} - -void -xjob(void) -{ - int i; - Thread *job; - - for(i=0, job = shell.jobs; job; job = job->link, i++) - report(job,i); - - poplist(); -} - -void -xfg(void) -{ - int i; - Thread *job, *old; - - popword(); // fg - - /* get input job id */ - if(!runner->args->word){ - print(shell.err, "usage: fg [pid|\%num]\n"); - poplist(); - return; - } - - i = atoi(runner->args->word->str); - popword(); // [pid|num] - - for(job=shell.jobs; i > 0; job=job->link, --i) - ; - - poplist(); // this goes here? - - wakeup(job); - job->caller = runner, runner = job; // XXX: can this leave zombies? - foreground(job, 1); -} - -void -xboot(int argc, char *argv[]) -{ - int i; - Code bootstrap[32]; - char num[12]; - - i = 0; - 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 = Xdollar; - bootstrap[i++].f = Xword; - bootstrap[i++].s = "/dev/stdin"; - bootstrap[i++].f = Xword; - bootstrap[i++].s="."; - bootstrap[i++].f = Xbasic; - bootstrap[i++].f = Xexit; - bootstrap[i].i = 0; - - run(bootstrap, 1, nil, 0); - runner->pid = runner->pgid = shell.pid; - pushlist(); // prime bootstrap argv - - argv0 = strdup(argv[0]); - for(i = argc-1; i > 0; --i) - pushword(argv[i]); - - /* main interpreter loop */ - for(;;){ - runner->code.i++; - (*runner->code.exe[runner->code.i-1].f)(); - } -} - -// ----------------------------------------------------------------------- -// exported interpreter bytecode - -void -Xmark(void) -{ - pushlist(); -} - -void -Xword(void) -{ - pushword(runner->code.exe[runner->code.i++].s); -} - -void -Xtrue(void) -{ - if(!runner->status){ - assert(runner->wait.status == Pdone); - runner->code.i++; - deljob(runner); - runner->pgid = -1; - }else - runner->code.i = runner->code.exe[runner->code.i].i; -} - -void -Xfalse(void) -{ - if(runner->status){ - assert(runner->wait.status == Pdone); - runner->code.i++; - deljob(runner); - runner->pgid = -1; - } else - runner->code.i = runner->code.exe[runner->code.i].i; -} - -void -Xgoto(void) -{ - runner->code.i = runner->code.exe[runner->code.i].i; -} - -void -Xfor(void) -{ - if(!runner->args->word){ - poplist(); - runner->code.i = runner->code.exe[runner->code.i].i; - }else{ - freelist(runner->local->val); - - runner->local->val = runner->args->word; - runner->local->new = 1; - runner->args->word = runner->args->word->link; - - runner->local->val->link = nil; - runner->code.i++; - } - -} - -static -Word* -catlist(Word *l, Word *r, Word *tail) -{ - Word *w; - char *buf; - - if(l->link || r->link) - tail = catlist( (!l->link)?l:l->link, (!r->link)?r:r->link, tail); - - buf = emalloc(strlen(l->str)+strlen(r->str)+1); - strcpy(buf, l->str); - strcat(buf, r->str); - - w = makeword(buf, tail); - efree(buf); - - return w; -} - -void -Xconcatenate(void) -{ - int rn, ln; - Word *l = runner->args->word; - Word *r = runner->args->link->word; - Word *w = runner->args->link->link->word; - - ln = count(l), rn = count(r); - if(ln != 0 || rn != 0) { - if(ln == 0 || rn == 0){ - Xerror("null list in concatenation\n"); - return; - } - if(ln != 1 && rn != 1 && ln != rn) { - Xerror("mismatched list lengths in concatenation\n"); - return; - } - w = catlist(l, r, w); - } - - poplist(); - poplist(); - runner->args->word = w; -} - -void -Xdollar(void) -{ - int n; - char *s, *t; - Word *a, *star; - - if(count(runner->args->word)!=1){ - Xerror("variable name not singleton!\n"); - return; - } - s = runner->args->word->str; - // deglob(s); - n = 0; - - for(t = s;'0'<=*t && *t<='9';t++) - n = n*10+*t-'0'; - - a = runner->args->link->word; - - if(n==0 || *t) - a = copywords(var(s)->val, a); - else{ - star = var("*")->val; - if(star && 1<=n && n<=count(star)){ - while(--n) - star = star->link; - - a = makeword(star->str, a); - } - } - - poplist(); - runner->args->word = a; -} - -static -Word* -cpwords(Word *array, Word *tail, int n) -{ - Word *cp, **end; - - cp = nil, end = &cp; - while(n-- > 0){ - *end = makeword(array->str, nil); - end = &(*end)->link; - array = array->link; - } - *end = tail; - - return cp; -} - - -static -Word* -getindex(Word *array, int len, Word *index, Word *tail) -{ - char *s; - int n, m; - if(!index) - return tail; - - tail = getindex(array, len, index->link, tail); - - s = index->str; - //deglob(s) - - m = 0, n = 0; - while('0' <= *s && *s <= '9') - n = 10*n + (*s++ - '0'); - if(*s == '-'){ - if(*++s == 0) - m = len - n; - else{ - while('0' <= *s && *s <= '9') - m = 10*m + (*s++ - '0'); - m -= n; - } - } - - if(n<1 || n > len || m < 0) - return tail; - if(n+m > len) - m = len-n; - while(--n > 0) - array = array->link; - return cpwords(array, tail, m+1); -} - -void -Xindex(void) -{ - char *s; - Word *val, *ret; - - if(count(runner->args->word) != 1){ - Xerror("variable name not a singleton"); - return; - } - s = runner->args->word->str; - //deglob(s) - val = var(s)->val; - poplist(); - - ret = runner->args->link->word; // pointer to next stack frame - ret = getindex(val, count(val), runner->args->word, ret); - poplist(); - - // push result back on stack - runner->args->word = ret; -} - -void -Xjoin(void) -{ - int n; - char *s; - Word *arg, *elt; - - if(count(runner->args->word) != 1){ - Xerror("variable name is not singleton\n"); - return; - } - - s = runner->args->word->str; - // deglob(s) - - arg = var(s)->val; - poplist(); - - n = count(arg); - if(n==0){ - pushword(""); - return; - } - - for(elt = arg; elt; elt=elt->link) - n += strlen(elt->str); - - s = emalloc(n); - if(arg){ - strcpy(s, arg->str); - for(elt = arg->link; elt; elt = elt->link){ - strcat(s, " "); - strcat(s, elt->str); - } - }else - s[0] = 0; - - pushword(s); - efree(s); -} - -void -Xassign(void) -{ - Var *v; - - if(count(runner->args->word)!=1){ - Xerror("variable name not singleton!\n"); - return; - } - //deglob(runq->argv->words->word); - v = var(runner->args->word->str); - poplist(); - - //globlist(); - freewords(v->val); - v->val = runner->args->word; - v->new = 1; - if(v->update) - v->update(v); - - runner->args->word = nil; - poplist(); -} - -void -Xreadcmd(void) -{ - Thread *root; - Word *prompt; - - flush(shell.err); - root = runner; - - resetprompt(); - - if(yyparse()){ - // resource cleanup? - if(runner->flag.eof) - Xreturn(); - else - --root->code.i; - }else{ - --root->code.i; /* re-execute Xreadcmd after codebuf runs */ - run(compiled, 1, root->local, 0); - } - - killzombies(); - freeparsetree(); -} - -void -Xlocal(void) -{ - if(count(runner->args->word)!=1){ - Xerror("variable name must be singleton\n"); - return; - } - //deglob(shell->args->word->str); - - runner->local = makevar(strdup(runner->args->word->str), runner->local); - runner->local->val = copywords(runner->args->link->word, nil); - runner->local->new = 1; - - poplist(); - poplist(); -} - -void -Xunlocal(void) -{ - Var *v = runner->local, *hide; - if(!v) - fatal("Xunlocal: no locals!\n", 0); - - runner->local = v->link; - hide = var(v->name); - hide->new = 1; - - efree(v->name); - freewords(v->val); - efree(v); -} - -void -Xasync(void) -{ - int pid; - /* - int null = open("/dev/null", 0); - if(!null){ - Xerror("can not open /dev/null\n"); - return; - } - */ - - switch(pid=fork()){ - case -1: - // close(null); - Xerror("fork failed: try again"); - break; - - case 0: // child in background - initchild(runner,0); - /* pushredir(Ropen, null, 0); */ - - run(runner->code.exe, runner->code.i+1, runner->local, 0); - runner->caller = nil; - runner->flag.user = 0; - break; - - default: // parent in foreground - initparent(runner,pid,1); - // close(null); - - runner->code.i = runner->code.exe[runner->code.i].i; /* jump to end of async command */ - /* don't wait: continue running */ - } -} - -void -Xsubshell(void) -{ - int pid, user; - - user = runner->flag.user; - switch(pid=fork()){ - case -1: - Xerror("fork failed: try again"); - break; - - case 0: // child - initchild(runner, 1); - run(runner->code.exe, runner->code.i+1, runner->local, 1); - runner->caller = nil; - break; - - default: // parent - initparent(runner, pid, 0); // relinquish control - waitfor(runner, pid); // wait until child finishes - if(user){ - tcsetpgrp(0, shell.pid); - runner->flag.user = 1; // take control - } - - runner->code.i = runner->code.exe[runner->code.i].i; // jump to end of subshell command and continue execution - } -} - -void -Xpipewait(void) -{ - foreground(runner, 0); -} - -void -Xpipe(void) -{ - Thread *orig; - int pc, pid, lfd, rfd, pfd[2]; - - orig = runner; - pc = orig->code.i; - lfd = orig->code.exe[pc++].i; - rfd = orig->code.exe[pc++].i; - - if(pipe(pfd)<0){ - Xerror("can't get pipe\n"); - return; - } - - switch(pid=fork()){ - case -1: - Xerror("try again"); - break; - case 0: // child - initchild(runner,1); - - /* child 0 (writer) forked process */ - run(runner->code.exe, pc+2, runner->local, 1); - runner->caller = nil; - - close(pfd[0]); - pushredir(Ropen, pfd[1], lfd); - break; - - default: // parent - initparent(runner,pid,0); - - /* child 1 (reader) subprocess*/ - run(runner->code.exe, runner->code.exe[pc].i, runner->local, 1); - - close(pfd[1]); - pushredir(Ropen, pfd[0], rfd); - - orig->code.i = orig->code.exe[pc+1].i; - break; - } -} - -void -Xbasic(void) -{ - Var *v; - Word *arg; - int pid, status; - struct Builtin *b; - - arg = runner->args->word; - if(!arg){ - Xerror("empty argument list\n"); - return; - } - - v = var(arg->str); - if(v->func){ - return; - } - - // see if it matches a builtin - for(b = builtin; b->name; b++){ - if(strcmp(b->name, arg->str)==0){ - b->func(); - return; - } - } - - /* if we are here then it's an external command */ - if(exitsnext()){ // if we exit immediately, no need to fork - pushword("exec"); - xx(); - Xexit(); - } - - // run the external command - if((pid = xforkx()) < 0) { - Xerror("try again"); - return; - } - - poplist(); - foreground(runner, 0); // waits for child -} - -void -Xcount(void) -{ - Word *arg; - char *str, num[12]; - - if(count(runner->args->word) != 1){ - Xerror("variable name not a singleton\n"); - return; - } - - str = runner->args->word->str; - arg = var(str)->val; - poplist(); - - itoa(num, count(arg)); - pushword(num); -} - -void -Xflat(void) -{ - int len; - char *str; - Word *arg, *a; - - if(count(runner->args->word)!=1){ - Xerror("variable name is not a singleton\n"); - return; - } - - str = runner->args->word->str; - arg = var(str)->val; - poplist(); - - len = count(arg); - if(!len){ - pushword(""); - return; - } - - for(a=arg; a; a=a->link) - len += strlen(a->str); - - str = emalloc(len); - if(arg){ - strcpy(str, arg->str); - for(a = arg->link; a; a = a->link){ - strcat(str," "); - strcat(str,a->str); - } - }else - str[0] = 0; - - pushword(str); - efree(str); -} - -void -Xbang(void) -{ - if(runner->status) - runner->status = 0; - else - runner->status = 1; -} - -void -Xpopredir(void) -{ - Redir *r = runner->redir.end; - if(!r) - fatal("attempted to pop a nil redir\n"); - - runner->redir.end = runner->redir.end->link; - if(r->type==Ropen) - close(r->from); - - efree(r); -} - -void -Xreturn(void) -{ - Thread *curr = runner; - - switch(curr->wait.status){ - /* - * If our job is still running or suspended we must: - * 1. move program one step back to rerun Xreturn upon recall - * 2. return to our calling thread - * 3. don't free! - */ - case Prun: - report(curr, 0); - curr->flag.user = 0; - case Pstop: - curr->code.i--; - runner = curr->caller; - curr->caller = nil; // detach job - return; - /* - * If our job has finished: - * 1. remove from our list - * 2. continue to clean up its memory - */ - case Pdone: - deljob(curr); - /* fallthrough */ - default: - ; - } - - undoredirs(); - - while(curr->args) - poplist(); - freecode(curr->code.exe); - efree(curr->wait.on); - - runner = curr->caller; - efree(curr); - if(!runner) - exit(0); -} - -void -Xexit(void) -{ - exit(runner->status); -} - -void -Xerror(char *msg) -{ - print(shell.err, "rc: %s", msg); - flush(shell.err); - while(!runner->flag.user) - Xreturn(); -} - -- cgit v1.2.1