1147 lines
19 KiB
C
Executable file
1147 lines
19 KiB
C
Executable file
#define Extern extern
|
|
#include <sys/types.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <setjmp.h>
|
|
#include <stddef.h>
|
|
#include <time.h>
|
|
#include <sys/times.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
#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; i<NOFILE; i++)
|
|
close(i);
|
|
if (resetsig) {
|
|
signal(SIGINT, SIG_DFL);
|
|
signal(SIGQUIT, SIG_DFL);
|
|
}
|
|
if (t->type == 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) {
|
|
int e=errno;
|
|
prs(cp);
|
|
if (iop->io_flag&IOHERE) prs(iop->io_name);
|
|
prs(": cannot ");
|
|
prs(msg);
|
|
prs(" (");
|
|
prs(strerror(e));
|
|
warn(")");
|
|
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);
|
|
}
|
|
|