1148 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1148 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);
 | 
						|
}
 | 
						|
 |