aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/rc/exec.c')
-rw-r--r--sys/cmd/rc/exec.c1267
1 files changed, 0 insertions, 1267 deletions
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 <sys/wait.h>
-
-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();
-}
-