#define Extern extern #include #include #define _NSIG NSIG #include #include #include #include #include #include #include #undef NULL #include "sh.h" /* -------- exec.c -------- */ /* #include "sh.h" */ /* * execute tree */ static char *signame[] = { "Signal 0", "Hangup", (char *)NULL, /* interrupt */ "Quit", "Illegal instruction", "Trace/BPT trap", "Abort", "EMT trap", "Floating exception", "Killed", "Bus error", "Memory fault", "Bad system call", (char *)NULL, /* broken pipe */ "Alarm clock", "Terminated", }; #define NSIGNAL (sizeof(signame)/sizeof(signame[0])) _PROTOTYPE(static int forkexec, (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked )); _PROTOTYPE(static int parent, (void)); _PROTOTYPE(int iosetup, (struct ioword *iop, int pipein, int pipeout )); _PROTOTYPE(static void echo, (char **wp )); _PROTOTYPE(static struct op **find1case, (struct op *t, char *w )); _PROTOTYPE(static struct op *findcase, (struct op *t, char *w )); _PROTOTYPE(static void brkset, (struct brkcon *bc )); _PROTOTYPE(int dolabel, (void)); _PROTOTYPE(int dochdir, (struct op *t )); _PROTOTYPE(int doshift, (struct op *t )); _PROTOTYPE(int dologin, (struct op *t )); _PROTOTYPE(int doumask, (struct op *t )); _PROTOTYPE(int doexec, (struct op *t )); _PROTOTYPE(int dodot, (struct op *t )); _PROTOTYPE(int dowait, (struct op *t )); _PROTOTYPE(int doread, (struct op *t )); _PROTOTYPE(int doeval, (struct op *t )); _PROTOTYPE(int dotrap, (struct op *t )); _PROTOTYPE(int getsig, (char *s )); _PROTOTYPE(void setsig, (int n, void (*f)())); _PROTOTYPE(int getn, (char *as )); _PROTOTYPE(int dobreak, (struct op *t )); _PROTOTYPE(int docontinue, (struct op *t )); _PROTOTYPE(static int brkcontin, (char *cp, int val )); _PROTOTYPE(int doexit, (struct op *t )); _PROTOTYPE(int doexport, (struct op *t )); _PROTOTYPE(int doreadonly, (struct op *t )); _PROTOTYPE(static void rdexp, (char **wp, void (*f)(), int key)); _PROTOTYPE(static void badid, (char *s )); _PROTOTYPE(int doset, (struct op *t )); _PROTOTYPE(void varput, (char *s, int out )); _PROTOTYPE(int dotimes, (void)); int execute(t, pin, pout, act) register struct op *t; int *pin, *pout; int act; { register struct op *t1; int i, pv[2], rv, child, a; char *cp, **wp, **wp2; struct var *vp; struct brkcon bc; if (t == NULL) return(0); rv = 0; a = areanum++; wp = (wp2 = t->words) != NULL ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) : NULL; switch(t->type) { case TPAREN: case TCOM: rv = forkexec(t, pin, pout, act, wp, &child); if (child) { exstat = rv; leave(); } break; case TPIPE: if ((rv = openpipe(pv)) < 0) break; pv[0] = remap(pv[0]); pv[1] = remap(pv[1]); (void) execute(t->left, pin, pv, 0); rv = execute(t->right, pv, pout, 0); break; case TLIST: (void) execute(t->left, pin, pout, 0); rv = execute(t->right, pin, pout, 0); break; case TASYNC: i = parent(); if (i != 0) { if (i != -1) { setval(lookup("!"), putn(i)); if (pin != NULL) closepipe(pin); if (talking) { prs(putn(i)); prs("\n"); } } else rv = -1; setstatus(rv); } else { signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); if (talking) signal(SIGTERM, SIG_DFL); talking = 0; if (pin == NULL) { close(0); open("/dev/null", 0); } exit(execute(t->left, pin, pout, FEXEC)); } break; case TOR: case TAND: rv = execute(t->left, pin, pout, 0); if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND)) rv = execute(t1, pin, pout, 0); break; case TFOR: if (wp == NULL) { wp = dolv+1; if ((i = dolc) < 0) i = 0; } else { i = -1; while (*wp++ != NULL) ; } vp = lookup(t->str); while (setjmp(bc.brkpt)) if (isbreak) goto broken; brkset(&bc); for (t1 = t->left; i-- && *wp != NULL;) { setval(vp, *wp++); rv = execute(t1, pin, pout, 0); } brklist = brklist->nextlev; break; case TWHILE: case TUNTIL: while (setjmp(bc.brkpt)) if (isbreak) goto broken; brkset(&bc); t1 = t->left; while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) rv = execute(t->right, pin, pout, 0); brklist = brklist->nextlev; break; case TIF: case TELIF: if (t->right != NULL) { rv = !execute(t->left, pin, pout, 0) ? execute(t->right->left, pin, pout, 0): execute(t->right->right, pin, pout, 0); } break; case TCASE: if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0) cp = ""; if ((t1 = findcase(t->left, cp)) != NULL) rv = execute(t1, pin, pout, 0); break; case TBRACE: /* if (iopp = t->ioact) while (*iopp) if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { rv = -1; break; } */ if (rv >= 0 && (t1 = t->left)) rv = execute(t1, pin, pout, 0); break; } broken: t->words = wp2; isbreak = 0; freehere(areanum); freearea(areanum); areanum = a; if (talking && intr) { closeall(); fail(); } if ((i = trapset) != 0) { trapset = 0; runtrap(i); } return(rv); } static int forkexec(t, pin, pout, act, wp, pforked) register struct op *t; int *pin, *pout; int act; char **wp; int *pforked; { int i, rv, (*shcom)(); register int f; char *cp; struct ioword **iopp; int resetsig; char **owp; owp = wp; resetsig = 0; *pforked = 0; shcom = NULL; rv = -1; /* system-detected error */ if (t->type == TCOM) { while ((cp = *wp++) != NULL) ; cp = *wp; /* strip all initial assignments */ /* not correct wrt PATH=yyy command etc */ if (flag['x']) echo (cp ? wp: owp); if (cp == NULL && t->ioact == NULL) { while ((cp = *owp++) != NULL && assign(cp, COPYV)) ; return(setstatus(0)); } else if (cp != NULL) shcom = inbuilt(cp); } t->words = wp; f = act; if (shcom == NULL && (f & FEXEC) == 0) { i = parent(); if (i != 0) { if (i == -1) return(rv); if (pin != NULL) closepipe(pin); return(pout==NULL? setstatus(waitfor(i,0)): 0); } if (talking) { signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); resetsig = 1; } talking = 0; intr = 0; (*pforked)++; brklist = 0; execflg = 0; } if (owp != NULL) while ((cp = *owp++) != NULL && assign(cp, COPYV)) if (shcom == NULL) export(lookup(cp)); #ifdef COMPIPE if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { err("piping to/from shell builtins not yet done"); return(-1); } #endif if (pin != NULL) { dup2(pin[0], 0); closepipe(pin); } if (pout != NULL) { dup2(pout[1], 1); closepipe(pout); } if ((iopp = t->ioact) != NULL) { if (shcom != NULL && shcom != doexec) { prs(cp); err(": cannot redirect shell command"); return(-1); } while (*iopp) if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) return(rv); } if (shcom) return(setstatus((*shcom)(t))); /* should use FIOCEXCL */ for (i=FDBASE; itype == TPAREN) exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); if (wp[0] == NULL) exit(0); cp = rexecve(wp[0], wp, makenv()); prs(wp[0]); prs(": "); warn(cp); if (!execflg) trap[0] = NULL; leave(); /* NOTREACHED */ } /* * common actions when creating a new child */ static int parent() { register int i; i = fork(); if (i != 0) { if (i == -1) warn("try again"); } return(i); } /* * 0< 1> are ignored as required * within pipelines. */ int iosetup(iop, pipein, pipeout) register struct ioword *iop; int pipein, pipeout; { register u; char *cp, *msg; if (iop->io_unit == IODEFAULT) /* take default */ iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1; if (pipein && iop->io_unit == 0) return(0); if (pipeout && iop->io_unit == 1) return(0); msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create"; if ((iop->io_flag & IOHERE) == 0) { cp = iop->io_name; if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL) return(1); } if (iop->io_flag & IODUP) { if (cp[1] || (!digit(*cp) && *cp != '-')) { prs(cp); err(": illegal >& argument"); return(1); } if (*cp == '-') iop->io_flag = IOCLOSE; iop->io_flag &= ~(IOREAD|IOWRITE); } switch (iop->io_flag) { case IOREAD: u = open(cp, 0); break; case IOHERE: case IOHERE|IOXHERE: u = herein(iop->io_name, iop->io_flag&IOXHERE); cp = "here file"; break; case IOWRITE|IOCAT: if ((u = open(cp, 1)) >= 0) { lseek(u, (long)0, 2); break; } case IOWRITE: u = creat(cp, 0666); break; case IODUP: u = dup2(*cp-'0', iop->io_unit); break; case IOCLOSE: close(iop->io_unit); return(0); } if (u < 0) { prs(cp); prs(": cannot "); warn(msg); return(1); } else { if (u != iop->io_unit) { dup2(u, iop->io_unit); close(u); } } return(0); } static void echo(wp) register char **wp; { register i; prs("+"); for (i=0; wp[i]; i++) { if (i) prs(" "); prs(wp[i]); } prs("\n"); } static struct op ** find1case(t, w) struct op *t; char *w; { register struct op *t1; struct op **tp; register char **wp, *cp; if (t == NULL) return((struct op **)NULL); if (t->type == TLIST) { if ((tp = find1case(t->left, w)) != NULL) return(tp); t1 = t->right; /* TPAT */ } else t1 = t; for (wp = t1->words; *wp;) if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) return(&t1->left); return((struct op **)NULL); } static struct op * findcase(t, w) struct op *t; char *w; { register struct op **tp; return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL); } /* * Enter a new loop level (marked for break/continue). */ static void brkset(bc) struct brkcon *bc; { bc->nextlev = brklist; brklist = bc; } /* * Wait for the last process created. * Print a message for each process found * that was killed by a signal. * Ignore interrupt signals while waiting * unless `canintr' is true. */ int waitfor(lastpid, canintr) register int lastpid; int canintr; { register int pid, rv; int s; int oheedint = heedint; heedint = 0; rv = 0; do { pid = wait(&s); if (pid == -1) { if (errno != EINTR || canintr) break; } else { if ((rv = WAITSIG(s)) != 0) { if (rv < NSIGNAL) { if (signame[rv] != NULL) { if (pid != lastpid) { prn(pid); prs(": "); } prs(signame[rv]); } } else { if (pid != lastpid) { prn(pid); prs(": "); } prs("Signal "); prn(rv); prs(" "); } if (WAITCORE(s)) prs(" - core dumped"); if (rv >= NSIGNAL || signame[rv]) prs("\n"); rv = -1; } else rv = WAITVAL(s); } } while (pid != lastpid); heedint = oheedint; if (intr) if (talking) { if (canintr) intr = 0; } else { if (exstat == 0) exstat = rv; onintr(0); } return(rv); } int setstatus(s) register int s; { exstat = s; setval(lookup("?"), putn(s)); return(s); } /* * PATH-searching interface to execve. * If getenv("PATH") were kept up-to-date, * execvp might be used. */ char * rexecve(c, v, envp) char *c, **v, **envp; { register int i; register char *sp, *tp; int eacces = 0, asis = 0; sp = any('/', c)? "": path->value; asis = *sp == '\0'; while (asis || *sp != '\0') { asis = 0; tp = e.linep; for (; *sp != '\0'; tp++) if ((*tp = *sp++) == ':') { asis = *sp == '\0'; break; } if (tp != e.linep) *tp++ = '/'; for (i = 0; (*tp++ = c[i++]) != '\0';) ; execve(e.linep, v, envp); switch (errno) { case ENOEXEC: *v = e.linep; tp = *--v; *v = e.linep; execve("/bin/sh", v, envp); *v = tp; return("no Shell"); case ENOMEM: return("program too big"); case E2BIG: return("argument list too long"); case EACCES: eacces++; break; } } return(errno==ENOENT ? "not found" : "cannot execute"); } /* * Run the command produced by generator `f' * applied to stream `arg'. */ int run(argp, f) struct ioarg *argp; int (*f)(); { struct op *otree; struct wdblock *swdlist; struct wdblock *siolist; jmp_buf ev, rt; xint *ofail; int rv; areanum++; swdlist = wdlist; siolist = iolist; otree = outtree; ofail = failpt; rv = -1; if (newenv(setjmp(errpt = ev)) == 0) { wdlist = 0; iolist = 0; pushio(argp, f); e.iobase = e.iop; yynerrs = 0; if (setjmp(failpt = rt) == 0 && yyparse() == 0) rv = execute(outtree, NOPIPE, NOPIPE, 0); quitenv(); } wdlist = swdlist; iolist = siolist; failpt = ofail; outtree = otree; freearea(areanum--); return(rv); } /* -------- do.c -------- */ /* #include "sh.h" */ /* * built-in commands: doX */ int dolabel() { return(0); } int dochdir(t) register struct op *t; { register char *cp, *er; if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) er = ": no home directory"; else if(chdir(cp) < 0) er = ": bad directory"; else return(0); prs(cp != NULL? cp: "cd"); err(er); return(1); } int doshift(t) register struct op *t; { register n; n = t->words[1]? getn(t->words[1]): 1; if(dolc < n) { err("nothing to shift"); return(1); } dolv[n] = dolv[0]; dolv += n; dolc -= n; setval(lookup("#"), putn(dolc)); return(0); } /* * execute login and newgrp directly */ int dologin(t) struct op *t; { register char *cp; if (talking) { signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); } cp = rexecve(t->words[0], t->words, makenv()); prs(t->words[0]); prs(": "); err(cp); return(1); } int doumask(t) register struct op *t; { register int i, n; register char *cp; if ((cp = t->words[1]) == NULL) { i = umask(0); umask(i); for (n=3*4; (n-=3) >= 0;) putc('0'+((i>>n)&07)); putc('\n'); } else { for (n=0; *cp>='0' && *cp<='9'; cp++) n = n*8 + (*cp-'0'); umask(n); } return(0); } int doexec(t) register struct op *t; { register i; jmp_buf ex; xint *ofail; t->ioact = NULL; for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++) ; if (i == 0) return(1); execflg = 1; ofail = failpt; if (setjmp(failpt = ex) == 0) execute(t, NOPIPE, NOPIPE, FEXEC); failpt = ofail; execflg = 0; return(1); } int dodot(t) struct op *t; { register i; register char *sp, *tp; char *cp; if ((cp = t->words[1]) == NULL) return(0); sp = any('/', cp)? ":": path->value; while (*sp) { tp = e.linep; while (*sp && (*tp = *sp++) != ':') tp++; if (tp != e.linep) *tp++ = '/'; for (i = 0; (*tp++ = cp[i++]) != '\0';) ; if ((i = open(e.linep, 0)) >= 0) { exstat = 0; next(remap(i)); return(exstat); } } prs(cp); err(": not found"); return(-1); } int dowait(t) struct op *t; { register i; register char *cp; if ((cp = t->words[1]) != NULL) { i = getn(cp); if (i == 0) return(0); } else i = -1; setstatus(waitfor(i, 1)); return(0); } int doread(t) struct op *t; { register char *cp, **wp; register nb; register int nl = 0; if (t->words[1] == NULL) { err("Usage: read name ..."); return(1); } for (wp = t->words+1; *wp; wp++) { for (cp = e.linep; !nl && cp < elinep-1; cp++) if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) || (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value))) break; *cp = 0; if (nb <= 0) break; setval(lookup(*wp), e.linep); } return(nb <= 0); } int doeval(t) register struct op *t; { return(RUN(awordlist, t->words+1, wdchar)); } int dotrap(t) register struct op *t; { register int n, i; register int resetsig; if (t->words[1] == NULL) { for (i=0; i<=_NSIG; i++) if (trap[i]) { prn(i); prs(": "); prs(trap[i]); prs("\n"); } return(0); } resetsig = digit(*t->words[1]); for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { n = getsig(t->words[i]); xfree(trap[n]); trap[n] = 0; if (!resetsig) { if (*t->words[1] != '\0') { trap[n] = strsave(t->words[1], 0); setsig(n, sig); } else setsig(n, SIG_IGN); } else { if (talking) if (n == SIGINT) setsig(n, onintr); else setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); else setsig(n, SIG_DFL); } } return(0); } int getsig(s) char *s; { register int n; if ((n = getn(s)) < 0 || n > _NSIG) { err("trap: bad signal number"); n = 0; } return(n); } void setsig(n, f) register n; _PROTOTYPE(void (*f), (int)); { if (n == 0) return; if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) { ourtrap[n] = 1; signal(n, f); } } int getn(as) char *as; { register char *s; register n, m; s = as; m = 1; if (*s == '-') { m = -1; s++; } for (n = 0; digit(*s); s++) n = (n*10) + (*s-'0'); if (*s) { prs(as); err(": bad number"); } return(n*m); } int dobreak(t) struct op *t; { return(brkcontin(t->words[1], 1)); } int docontinue(t) struct op *t; { return(brkcontin(t->words[1], 0)); } static int brkcontin(cp, val) register char *cp; int val; { register struct brkcon *bc; register nl; nl = cp == NULL? 1: getn(cp); if (nl <= 0) nl = 999; do { if ((bc = brklist) == NULL) break; brklist = bc->nextlev; } while (--nl); if (nl) { err("bad break/continue level"); return(1); } isbreak = val; longjmp(bc->brkpt, 1); /* NOTREACHED */ } int doexit(t) struct op *t; { register char *cp; execflg = 0; if ((cp = t->words[1]) != NULL) setstatus(getn(cp)); leave(); /* NOTREACHED */ } int doexport(t) struct op *t; { rdexp(t->words+1, export, EXPORT); return(0); } int doreadonly(t) struct op *t; { rdexp(t->words+1, ronly, RONLY); return(0); } static void rdexp(wp, f, key) register char **wp; void (*f)(); int key; { if (*wp != NULL) { for (; *wp != NULL; wp++) if (checkname(*wp)) (*f)(lookup(*wp)); else badid(*wp); } else putvlist(key, 1); } static void badid(s) register char *s; { prs(s); err(": bad identifier"); } int doset(t) register struct op *t; { register struct var *vp; register char *cp; register n; if ((cp = t->words[1]) == NULL) { for (vp = vlist; vp; vp = vp->next) varput(vp->name, 1); return(0); } if (*cp == '-') { /* bad: t->words++; */ for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++) ; if (*++cp == 0) flag['x'] = flag['v'] = 0; else for (; *cp; cp++) switch (*cp) { case 'e': if (!talking) flag['e']++; break; default: if (*cp>='a' && *cp<='z') flag[*cp]++; break; } setdash(); } if (t->words[1]) { t->words[0] = dolv[0]; for (n=1; t->words[n]; n++) setarea((char *)t->words[n], 0); dolc = n-1; dolv = t->words; setval(lookup("#"), putn(dolc)); setarea((char *)(dolv-1), 0); } return(0); } void varput(s, out) register char *s; int out; { if (letnum(*s)) { write(out, s, strlen(s)); write(out, "\n", 1); } } #define SECS 60L #define MINS 3600L int dotimes() { struct tms tbuf; times(&tbuf); prn((int)(tbuf.tms_cutime / MINS)); prs("m"); prn((int)((tbuf.tms_cutime % MINS) / SECS)); prs("s "); prn((int)(tbuf.tms_cstime / MINS)); prs("m"); prn((int)((tbuf.tms_cstime % MINS) / SECS)); prs("s\n"); return(0); } struct builtin { char *command; int (*fn)(); }; static struct builtin builtin[] = { ":", dolabel, "cd", dochdir, "shift", doshift, "exec", doexec, "wait", dowait, "read", doread, "eval", doeval, "trap", dotrap, "break", dobreak, "continue", docontinue, "exit", doexit, "export", doexport, "readonly", doreadonly, "set", doset, ".", dodot, "umask", doumask, "login", dologin, "newgrp", dologin, "times", dotimes, 0, }; int (*inbuilt(s))() register char *s; { register struct builtin *bp; for (bp = builtin; bp->command != NULL; bp++) if (strcmp(bp->command, s) == 0) return(bp->fn); return((int(*)())NULL); }